<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>rest-assured wiki翻译 | manor blog</title>
  
    <meta name="keywords" content=" rest ">
  
  <meta name="description" content="rest-assured wiki翻译 | manor blog">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description" content="个人简介pgmanor，程序员一名。 喜欢研究技术，涉及GO、JAVA、微服务、大数据领域。目前主要从事微服务。 联系方式 QQ : 2307546059 (pgmanor) 邮箱 :pgmanor@qq.com">
<meta property="og:type" content="website">
<meta property="og:title" content="关于">
<meta property="og:url" content="https://pgmanor.gitee.io/blog/about/index.html">
<meta property="og:site_name" content="manor blog">
<meta property="og:description" content="个人简介pgmanor，程序员一名。 喜欢研究技术，涉及GO、JAVA、微服务、大数据领域。目前主要从事微服务。 联系方式 QQ : 2307546059 (pgmanor) 邮箱 :pgmanor@qq.com">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-12-30T16:00:00.000Z">
<meta property="article:modified_time" content="2020-12-15T14:30:19.631Z">
<meta property="article:author" content="pgmanor">
<meta property="article:tag" content="pgmanor">
<meta property="article:tag" content="blog">
<meta name="twitter:card" content="summary">


<link rel="icon" href="/blog/img/pgmanor_blog.svg">

<link href="/blog/css/style.css?v=1.0.1x" rel="stylesheet">

<link href="/blog/css/hl_theme/atom-light.css?v=1.0.1x" rel="stylesheet">

<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/fontawesome.min.js" rel="stylesheet">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="/blog/js/jquery.autocomplete.min.js?v=1.0.1x" ></script>
<script src="/blog/js/titleTip.js?v=1.0.1x" ></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.3/highlight.min.js"></script>
<script>
    hljs.initHighlightingOnLoad();
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>



<script src="/blog/js/iconfont.js?v=1.0.1x" ></script>

<meta name="generator" content="Hexo 4.2.1"></head>
<div style="display: none">
  <input class="theme_disqus_on" value="false">
  <input class="theme_preload_comment" value="false">
  <input class="theme_blog_path" value="/blog">
  <input id="theme_highlight_on" value="true" />
  <input id="theme_code_copy" value="true" />
</div>




<body>
<aside class="nav">
    <div class="nav-left">
        <a href="/blog/" class="avatar_target">
    <img class="avatar" src="/blog/img/pgmanor_blog.svg" />
</a>
<div class="author">
    <span>pgmanor</span>
</div>

<div class="icon">
    
        
        <a title="github" href="https://gitee.com/pgmanor" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-github"></use>
                </svg>
            
        </a>
        
    
        
        <a title="csdn" href="https://blog.csdn.net/u011622109" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-csdn"></use>
                </svg>
            
        </a>
        
    
        
        <a title="email" href="mailto:pgmanor@qq.com" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-email"></use>
                </svg>
            
        </a>
        
    
        
        <a title="qq" href="http://wpa.qq.com/msgrd?v=3&uin=2307546059&site=qq&menu=yes" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-qq"></use>
                </svg>
            
        </a>
        
    
        
        <a title="kugou" href="https://www.kugou.com/" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-kugou"></use>
                </svg>
            
        </a>
        
    
        
        <a title="neteasemusic" href="https://music.163.com/" target="_blank">
            
                <svg class="iconfont-svg" aria-hidden="true">
                    <use xlink:href="#icon-neteasemusic"></use>
                </svg>
            
        </a>
        
    
</div>



<a class="more-menus">更多菜单</a>


<ul>
    <li><div class="all active">全部文章<small>(129)</small></div></li>
    
        
            
            <li><div data-rel="博客"><i class="fold iconfont icon-right"></i>博客<small>(108)</small></div>
                
                    <ul class="sub hide">
                        
                        <li><div data-rel="B---大数据">B---大数据<small>(4)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="C-----并发">C-----并发<small>(1)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="D--数据库">D--数据库<small>(16)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="D-devops">D-devops<small>(5)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="F-----架构">F-----架构<small>(10)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="I-----面试">I-----面试<small>(2)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="J-----java">J-----java<small>(14)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="M--微服务">M--微服务<small>(6)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="P-python">P-python<small>(9)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="T-----工具">T-----工具<small>(26)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="T-----测试">T-----测试<small>(6)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="W-----前端">W-----前端<small>(4)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="W-window">W-window<small>(3)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="微服务">微服务<small>(2)</small></div>
                            
                        </li>
                            
                    </ul>
                
            </li>
            
        
    
        
            
            <li><div data-rel="农场"><i class="fold iconfont icon-right"></i>农场<small>(10)</small></div>
                
                    <ul class="sub hide">
                        
                        <li><div data-rel="微服务">微服务<small>(1)</small></div>
                            
                        </li>
                            
                        <li><div data-rel="算法">算法<small>(8)</small></div>
                            
                        </li>
                            
                    </ul>
                
            </li>
            
        
    
        
            
            <li><div data-rel="项目">项目<small>(9)</small></div>
                
            </li>
            
        
    
        
            
            <li><div data-rel="加密">加密<small>(2)</small></div>
                
            </li>
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
        
            
        
    
</ul>
<div class="left-bottom">
    <div class="menus">
    
    
    
    <a class="dynamic-menu " target="_blank"  href="https://www.iworkh.com/">iworkh</a>
    
    
    <a class="dynamic-menu " target="_blank"  href="https://gitee.com/pgmanor">gitee</a>
    
    </div>
    <div><a class="about  hasFriend  site_url"  href="/blog/about">关于</a><a style="width: 50%"  class="friends">友链</a></div>
</div>
<input type="hidden" id="iworkh_site_posts_number" value="129">
<input type="hidden" id="iworkh_site_word_count" value="273k">
<div style="display: none">
    <span id="busuanzi_value_site_uv"></span>
    <span id="busuanzi_value_site_pv"></span>
</div>

    </div>
    <div class="nav-right">
        <div class="friends-area">
    <div class="friends-title">
        友情链接
        <i class="back-title-list"></i>
    </div>
    <div class="friends-content">
        <ul>
            
            <li><a target="_blank" href="https://www.iworkh.com">iworkh</a></li>
            
            <li><a target="_blank" href="https://www.iworkh.com/download/share/">下载地址</a></li>
            
            <li><a target="_blank" href="http://yelog.org/">叶落阁</a></li>
            
        </ul>
    </div>
</div>
        <div class="title-list">
    <form onkeydown="if(event.keyCode === 13){return false;}">
        <input id="local-search-input" class="search" type="text" placeholder="in: 开头全文搜索" />
        <i class="cross"></i>
        <span>
            <label for="tagswitch">T:</label>
            <input id="tagswitch" type="checkbox" style="display: none" />
            <i id="tagsWitchIcon"></i>
        </span>
    </form>
    <div class="tags-list">
    
    <li class="article-tag-list-item">
        <a class="color4">AQS</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">attr</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">aysnc</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">beanmap</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">bigdecimal</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">blog</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">chrome</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">dict</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">dll</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">doc</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">docker</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">domain</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">elementadmin</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">es</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">excel</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">farm</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">fastjson</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">func</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">git</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">github</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">guide</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">hadoop</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">hexo</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">idea</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">initialzr</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">jackson</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">java</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">jboss</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">jdni</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">jetbrains</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">jfinalshell</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">joplin</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">JPA</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">junit</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">jupyter</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">keepavlie</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">kill</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">linux</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">LocalDate</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">lock</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">markdown</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">maven</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">message</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">mock</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">mq</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">mycat</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">mysql</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">nginx</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">notebook</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">postman</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">powermock</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">python</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">redis</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">rest</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">sharding-jdbc</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">spark</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">springboot</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color2">testng</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">tornado</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color1">track</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">transactional</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">uuid</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">vuepress</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">web</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">windows</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">zookeeper</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">分库分表</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">分页</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">加密</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">启动</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">工具</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">并发</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">序列化</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">微服务</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">性能分析</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">手册</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color4">有道云</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">模板</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color5">百度云盘</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">算法</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">面试</a>
    </li>
    
    <li class="article-tag-list-item">
        <a class="color3">项目</a>
    </li>
    
    <div class="clearfix"></div>
</div>

    
    <div id="local-search-result">

    </div>
    
    <nav id="title-list-nav">
        
        <a id="top" class="农场 "
           href="/blog/2020/12/31/farm-manual-summary/"
           data-tag="手册,farm"
           data-author="pgmanor" >
            <span class="post-title" title="手册汇总">手册汇总</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a id="top" class="农场 微服务 "
           href="/blog/2020/12/31/farm-spring-boot-all-resources/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="Spring Boot全网优质教程汇总">Spring Boot全网优质教程汇总</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a id="top" class="加密 "
           href="/blog/2021/01/10/secret-farm-mysql/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql密钥">mysql密钥</span>
            <span class="post-date" title="2021-01-10 00:00:00">2021/01/10</span>
        </a>
        
        <a id="top" class="加密 "
           href="/blog/2020/12/31/secret-baidu-pandisk-share/"
           data-tag="百度云盘"
           data-author="pgmanor" >
            <span class="post-title" title="百度云盘分享链接">百度云盘分享链接</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a id="top" class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-jetbrains-idea/"
           data-tag="idea"
           data-author="pgmanor" >
            <span class="post-title" title="idea使用技巧">idea使用技巧</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a id="top" class="博客 T-----工具 "
           href="/blog/2021/03/14/blog-tool-online/"
           data-tag="blog"
           data-author="pgmanor" >
            <span class="post-title" title="常用在线工具">常用在线工具</span>
            <span class="post-date" title="2021-03-14 00:00:00">2021/03/14</span>
        </a>
        
        <a id="top" class="博客 W-----前端 "
           href="/blog/2020/12/31/blog-web/"
           data-tag="web"
           data-author="pgmanor" >
            <span class="post-title" title="前端常用工具">前端常用工具</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/09/12/project-guide-http/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="模拟http请求">模拟http请求</span>
            <span class="post-date" title="2021-09-12 00:00:00">2021/09/12</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/09/12/blog-tool-chrome-disable-cros/"
           data-tag="chrome"
           data-author="pgmanor" >
            <span class="post-title" title="禁用Chrome跨域">禁用Chrome跨域</span>
            <span class="post-date" title="2021-09-12 00:00:00">2021/09/12</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/09/04/project-guide-download-excel/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="vue和hutool工具实现excel下载">vue和hutool工具实现excel下载</span>
            <span class="post-date" title="2021-09-04 00:00:00">2021/09/04</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/09/04/project-guide-param-pass-array/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="axios参数传数组">axios参数传数组</span>
            <span class="post-date" title="2021-09-04 00:00:00">2021/09/04</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/08/15/blog-mysql-backup-cron/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="cron定时器">cron定时器</span>
            <span class="post-date" title="2021-08-15 00:00:00">2021/08/15</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/08/14/blog-mysql-backup-xtrabackup/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql备份-xtrabackup">mysql备份-xtrabackup</span>
            <span class="post-date" title="2021-08-14 00:00:00">2021/08/14</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/08/14/blog-mysql-backup-xtrabackup-scripts/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql备份-xtrabackup-脚本">mysql备份-xtrabackup-脚本</span>
            <span class="post-date" title="2021-08-14 00:00:00">2021/08/14</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/08/08/project-guide-devops-slowquery/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="SQL慢查询">SQL慢查询</span>
            <span class="post-date" title="2021-08-08 00:00:00">2021/08/08</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/08/08/blog-mysql-backup-summary/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql备份">mysql备份</span>
            <span class="post-date" title="2021-08-08 00:00:00">2021/08/08</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/08/08/project-guide-springboot-upgrade/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="springboot升级到2.5.x遇到的问题">springboot升级到2.5.x遇到的问题</span>
            <span class="post-date" title="2021-08-08 00:00:00">2021/08/08</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2021/08/07/blog-fw-es-install/"
           data-tag="es"
           data-author="pgmanor" >
            <span class="post-title" title="ElasticSearch安装和使用">ElasticSearch安装和使用</span>
            <span class="post-date" title="2021-08-07 00:00:00">2021/08/07</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/08/07/project-guide-log-analysis/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="日志分析">日志分析</span>
            <span class="post-date" title="2021-08-07 00:00:00">2021/08/07</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/08/07/project-guide-devops-monitor/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="运维监控">运维监控</span>
            <span class="post-date" title="2021-08-07 00:00:00">2021/08/07</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/08/01/blog-tool-postman/"
           data-tag="postman"
           data-author="pgmanor" >
            <span class="post-title" title="postman工具使用">postman工具使用</span>
            <span class="post-date" title="2021-08-01 00:00:00">2021/08/01</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/08/01/blog-tool-bug-track/"
           data-tag="track"
           data-author="pgmanor" >
            <span class="post-title" title="bug跟踪工具">bug跟踪工具</span>
            <span class="post-date" title="2021-08-01 00:00:00">2021/08/01</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/08/01/blog-java-kill/"
           data-tag="kill"
           data-author="pgmanor" >
            <span class="post-title" title="java项目如何优雅关闭程序">java项目如何优雅关闭程序</span>
            <span class="post-date" title="2021-08-01 00:00:00">2021/08/01</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2021/07/25/blog-spring-boot-logback/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="springboot logback多环境">springboot logback多环境</span>
            <span class="post-date" title="2021-07-25 00:00:00">2021/07/25</span>
        </a>
        
        <a  class="博客 W-----前端 "
           href="/blog/2021/06/18/blog-vue-element-admin-keepalive/"
           data-tag="keepavlie"
           data-author="pgmanor" >
            <span class="post-title" title="vue中keep alive失效">vue中keep alive失效</span>
            <span class="post-date" title="2021-06-18 00:00:00">2021/06/18</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/06/14/blog-java-start/"
           data-tag="启动"
           data-author="pgmanor" >
            <span class="post-title" title="java启动方式">java启动方式</span>
            <span class="post-date" title="2021-06-14 00:00:00">2021/06/14</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/05/31/project-guide-vue-component/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="vue封装组件">vue封装组件</span>
            <span class="post-date" title="2021-05-31 00:00:00">2021/05/31</span>
        </a>
        
        <a  class="项目 "
           href="/blog/2021/05/09/project-guide-vue-full-calendar/"
           data-tag="项目,guide"
           data-author="pgmanor" >
            <span class="post-title" title="vue-full-calendar日历">vue-full-calendar日历</span>
            <span class="post-date" title="2021-05-09 00:00:00">2021/05/09</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2021/05/04/blog-redis-local/"
           data-tag="redis"
           data-author="pgmanor" >
            <span class="post-title" title="嵌入redis和可视化界面">嵌入redis和可视化界面</span>
            <span class="post-date" title="2021-05-04 22:48:35">2021/05/04</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/03/14/blog-tool-doc/"
           data-tag="doc"
           data-author="pgmanor" >
            <span class="post-title" title="文档工具">文档工具</span>
            <span class="post-date" title="2021-03-14 00:00:00">2021/03/14</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/03/14/blog-jpa-anno-generatedValue/"
           data-tag="JPA"
           data-author="pgmanor" >
            <span class="post-title" title="JPA注解@GeneratedValue">JPA注解@GeneratedValue</span>
            <span class="post-date" title="2021-03-14 00:00:00">2021/03/14</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/03/14/blog-tool-chrome/"
           data-tag="chrome"
           data-author="pgmanor" >
            <span class="post-title" title="Chrome调试技巧">Chrome调试技巧</span>
            <span class="post-date" title="2021-03-14 00:00:00">2021/03/14</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/03/14/blog-vuepress-fulltext-search/"
           data-tag="vuepress"
           data-author="pgmanor" >
            <span class="post-title" title="vuepress支持全文搜索">vuepress支持全文搜索</span>
            <span class="post-date" title="2021-03-14 00:00:00">2021/03/14</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2021/03/07/blog-redis-type-string-sds/"
           data-tag="redis"
           data-author="pgmanor" >
            <span class="post-title" title="Redis为什么将String设计成SDS">Redis为什么将String设计成SDS</span>
            <span class="post-date" title="2021-03-07 00:00:00">2021/03/07</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2021/03/07/blog-redis-fast/"
           data-tag="redis"
           data-author="pgmanor" >
            <span class="post-title" title="Redis为什么这么快">Redis为什么这么快</span>
            <span class="post-date" title="2021-03-07 00:00:00">2021/03/07</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2021/03/07/blog-redis-type-six/"
           data-tag="redis"
           data-author="pgmanor" >
            <span class="post-title" title="Redis的6大数据类型">Redis的6大数据类型</span>
            <span class="post-date" title="2021-03-07 00:00:00">2021/03/07</span>
        </a>
        
        <a  class="博客 微服务 "
           href="/blog/2021/03/06/blog-spring-boot-h2/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="springboot整合h2">springboot整合h2</span>
            <span class="post-date" title="2021-03-06 00:00:00">2021/03/06</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/02/28/blog-java-md5/"
           data-tag="uuid"
           data-author="pgmanor" >
            <span class="post-title" title="MD5加密">MD5加密</span>
            <span class="post-date" title="2021-02-28 00:00:00">2021/02/28</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/02/28/blog-java-uuid/"
           data-tag="uuid"
           data-author="pgmanor" >
            <span class="post-title" title="UUID">UUID</span>
            <span class="post-date" title="2021-02-28 00:00:00">2021/02/28</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/02/28/blog-java-base64/"
           data-tag="uuid"
           data-author="pgmanor" >
            <span class="post-title" title="base64加解密">base64加解密</span>
            <span class="post-date" title="2021-02-28 00:00:00">2021/02/28</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2021/02/27/blog-java-new8-date-opertaion.md/"
           data-tag="LocalDate"
           data-author="pgmanor" >
            <span class="post-title" title="java8日期操作">java8日期操作</span>
            <span class="post-date" title="2021-02-27 00:00:00">2021/02/27</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/01/24/blog-jpa-entity-manager/"
           data-tag="JPA"
           data-author="pgmanor" >
            <span class="post-title" title="JPA之EntityManager">JPA之EntityManager</span>
            <span class="post-date" title="2021-01-24 00:00:00">2021/01/24</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2021/01/24/blog-jpa-relationship/"
           data-tag="JPA"
           data-author="pgmanor" >
            <span class="post-title" title="JPA表与表关系映射">JPA表与表关系映射</span>
            <span class="post-date" title="2021-01-24 00:00:00">2021/01/24</span>
        </a>
        
        <a  class="博客 W-----前端 "
           href="/blog/2021/01/24/blog-web-CodeMirror/"
           data-tag="web"
           data-author="pgmanor" >
            <span class="post-title" title="CodeMirror">CodeMirror</span>
            <span class="post-date" title="2021-01-24 00:00:00">2021/01/24</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/01/10/blog-vuepress-theme-password/"
           data-tag="vuepress"
           data-author="pgmanor" >
            <span class="post-title" title="vuepress-theme-reco源码密钥修改">vuepress-theme-reco源码密钥修改</span>
            <span class="post-date" title="2021-01-10 00:00:00">2021/01/10</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/01/03/blog-tool-encryption/"
           data-tag="加密"
           data-author="pgmanor" >
            <span class="post-title" title="在线加密工具">在线加密工具</span>
            <span class="post-date" title="2021-01-03 10:08:09">2021/01/03</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/01/02/blog-tool-jboss-password/"
           data-tag="jboss"
           data-author="pgmanor" >
            <span class="post-title" title="jboss数据库密码加解密">jboss数据库密码加解密</span>
            <span class="post-date" title="2021-01-02 00:00:00">2021/01/02</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2021/01/02/blog-tool-excel-hidden-col/"
           data-tag="excel"
           data-author="pgmanor" >
            <span class="post-title" title="excel隐藏空白列">excel隐藏空白列</span>
            <span class="post-date" title="2021-01-02 00:00:00">2021/01/02</span>
        </a>
        
        <a  class="博客 微服务 "
           href="/blog/2021/01/02/blog-spring-boot-run-withparam-windows/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="springboot项目多环境运行报错 windows">springboot项目多环境运行报错 windows</span>
            <span class="post-date" title="2021-01-02 00:00:00">2021/01/02</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-sort/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法8-排序">数据结构和算法8-排序</span>
            <span class="post-date" title="2020-12-31 08:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-search/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法7-搜索">数据结构和算法7-搜索</span>
            <span class="post-date" title="2020-12-31 07:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-graph/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法6-非线性-图">数据结构和算法6-非线性-图</span>
            <span class="post-date" title="2020-12-31 06:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-tree/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法5-非线性-树">数据结构和算法5-非线性-树</span>
            <span class="post-date" title="2020-12-31 05:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-linear-queue/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法4-线性-队列">数据结构和算法4-线性-队列</span>
            <span class="post-date" title="2020-12-31 04:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-linear-stack/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法3-线性-栈">数据结构和算法3-线性-栈</span>
            <span class="post-date" title="2020-12-31 03:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-linear-list/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法2-线性-链">数据结构和算法2-线性-链</span>
            <span class="post-date" title="2020-12-31 02:00:00">2020/12/31</span>
        </a>
        
        <a  class="农场 算法 "
           href="/blog/2020/12/31/farm-data-structures-algorithms-info/"
           data-tag="算法"
           data-author="pgmanor" >
            <span class="post-title" title="数据结构和算法1-介绍">数据结构和算法1-介绍</span>
            <span class="post-date" title="2020-12-31 01:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D-devops "
           href="/blog/2020/12/31/blog-devops-linux-jfinalshell/"
           data-tag="jfinalshell"
           data-author="pgmanor" >
            <span class="post-title" title="linux连接工具jfinalshell">linux连接工具jfinalshell</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python-tool-buildin-func/"
           data-tag="func"
           data-author="pgmanor" >
            <span class="post-title" title="👍python内置函数">👍python内置函数</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-jpa-query-multi-param/"
           data-tag="JPA"
           data-author="pgmanor" >
            <span class="post-title" title="JPA多条件查询">JPA多条件查询</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-jpa-query/"
           data-tag="JPA"
           data-author="pgmanor" >
            <span class="post-title" title="JPA自定义sql">JPA自定义sql</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2020/12/31/blog-fw-mq-message-missing/"
           data-tag="mq,message"
           data-author="pgmanor" >
            <span class="post-title" title="MQ如何保证消息不丢失?">MQ如何保证消息不丢失?</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 B---大数据 "
           href="/blog/2020/12/31/blog-hadoop-install-windows/"
           data-tag="hadoop"
           data-author="pgmanor" >
            <span class="post-title" title="hadoop开发环境搭建">hadoop开发环境搭建</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-mysql-lock-unlock-table/"
           data-tag="lock"
           data-author="pgmanor" >
            <span class="post-title" title="mysql数据库锁查询和释放">mysql数据库锁查询和释放</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-ai-python-spark-env/"
           data-tag="spark"
           data-author="pgmanor" >
            <span class="post-title" title="python spark开发环境搭建">python spark开发环境搭建</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-mysql-windows-zip-install/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql zip在windows上安装">mysql zip在windows上安装</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python_install/"
           data-tag="python"
           data-author="pgmanor" >
            <span class="post-title" title="python环境安装">python环境安装</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D-devops "
           href="/blog/2020/12/31/blog-devops-docker-introduction/"
           data-tag="docker"
           data-author="pgmanor" >
            <span class="post-title" title="👍docker入门看这一篇就够了">👍docker入门看这一篇就够了</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 I-----面试 "
           href="/blog/2020/12/31/blog-interview-company/"
           data-tag="面试"
           data-author="pgmanor" >
            <span class="post-title" title="IT互联网公司名单">IT互联网公司名单</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-base-domain/"
           data-tag="domain"
           data-author="pgmanor" >
            <span class="post-title" title="VO DTO DO PO你都了解吗?">VO DTO DO PO你都了解吗?</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-base-serializable/"
           data-tag="序列化"
           data-author="pgmanor" >
            <span class="post-title" title="java序列化">java序列化</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-hexo-theme-math/"
           data-tag="hexo"
           data-author="pgmanor" >
            <span class="post-title" title="hexo主题支持MathJax">hexo主题支持MathJax</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 C-----并发 "
           href="/blog/2020/12/31/blog-java-concurrent-aqs/"
           data-tag="AQS,并发"
           data-author="pgmanor" >
            <span class="post-title" title="java并发AQS">java并发AQS</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-java-dao-sharding-db/"
           data-tag="分库分表"
           data-author="pgmanor" >
            <span class="post-title" title="分库分表中间件-开源产品">分库分表中间件-开源产品</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 B---大数据 "
           href="/blog/2020/12/31/blog-spark-install-windows/"
           data-tag="spark"
           data-author="pgmanor" >
            <span class="post-title" title="spark开发环境搭建">spark开发环境搭建</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-jetbrains-crack/"
           data-tag="idea,jetbrains"
           data-author="pgmanor" >
            <span class="post-title" title="jetbrains全家桶破解">jetbrains全家桶破解</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2020/12/31/blog-spring-boot-multi-profiles/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="springboot多环境配置打包">springboot多环境配置打包</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-markdown-math-express/"
           data-tag="markdown"
           data-author="pgmanor" >
            <span class="post-title" title="markdown数学公式">markdown数学公式</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 I-----面试 "
           href="/blog/2020/12/31/blog-interview-java-question/"
           data-tag="面试"
           data-author="pgmanor" >
            <span class="post-title" title="java常见面试题">java常见面试题</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2020/12/31/blog-nginx-fast/"
           data-tag="nginx"
           data-author="pgmanor" >
            <span class="post-title" title="nginx为何这么快?">nginx为何这么快?</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2020/12/31/spring-initialzr/"
           data-tag="工具,initialzr"
           data-author="pgmanor" >
            <span class="post-title" title="spring initialzr环境编译发布">spring initialzr环境编译发布</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2020/12/31/blog-redis-memory-eliminate/"
           data-tag="redis"
           data-author="pgmanor" >
            <span class="post-title" title="Redis的内存淘汰策略">Redis的内存淘汰策略</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2020/12/31/blog-spring-pageable/"
           data-tag="分页"
           data-author="pgmanor" >
            <span class="post-title" title="vue+springboot分页交互">vue+springboot分页交互</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python_base/"
           data-tag="python"
           data-author="pgmanor" >
            <span class="post-title" title="python基本语法">python基本语法</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2020/12/31/blog-spring-transaction/"
           data-tag="transactional"
           data-author="pgmanor" >
            <span class="post-title" title="Transactional注解">Transactional注解</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/12/31/blog-test-ng/"
           data-tag="testng"
           data-author="pgmanor" >
            <span class="post-title" title="👍TestNG一篇足以">👍TestNG一篇足以</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/12/31/blog-test-mockito/"
           data-tag="mock"
           data-author="pgmanor" >
            <span class="post-title" title="👍mockito测试框架">👍mockito测试框架</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/12/31/blog-test-powermock/"
           data-tag="powermock"
           data-author="pgmanor" >
            <span class="post-title" title="powermock测试框架">powermock测试框架</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-blogs-all/"
           data-tag="blog"
           data-author="pgmanor" >
            <span class="post-title" title="优质博客和文章">优质博客和文章</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 W-window "
           href="/blog/2020/12/31/blog-tool-windows-dev-install/"
           data-tag="windows"
           data-author="pgmanor" >
            <span class="post-title" title="windows开发环境安装">windows开发环境安装</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-base-bigdecimal/"
           data-tag="bigdecimal"
           data-author="pgmanor" >
            <span class="post-title" title="BigDecimal正确使用了吗?">BigDecimal正确使用了吗?</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 W-----前端 "
           href="/blog/2020/12/31/blog-vue-element-admin/"
           data-tag="elementadmin"
           data-author="pgmanor" >
            <span class="post-title" title="vue element admin开发">vue element admin开发</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 M--微服务 "
           href="/blog/2020/12/31/blog-vue-springboot-package-publish/"
           data-tag="springboot"
           data-author="pgmanor" >
            <span class="post-title" title="vue+springboot打包发布">vue+springboot打包发布</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-java-dao-mycat/"
           data-tag="mycat"
           data-author="pgmanor" >
            <span class="post-title" title="分库分表中间件-MyCat">分库分表中间件-MyCat</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-connect-github/"
           data-tag="github"
           data-author="pgmanor" >
            <span class="post-title" title="github无法访问解决办法">github无法访问解决办法</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-install-windows/"
           data-tag="java"
           data-author="pgmanor" >
            <span class="post-title" title="jdk开发环境搭建">jdk开发环境搭建</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-ai-jupyter-notebook/"
           data-tag="jupyter"
           data-author="pgmanor" >
            <span class="post-title" title="jupyter notebook">jupyter notebook</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-chrome-plugin/"
           data-tag="chrome"
           data-author="pgmanor" >
            <span class="post-title" title="chrome插件">chrome插件</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-git-error-name-too-long/"
           data-tag="git"
           data-author="pgmanor" >
            <span class="post-title" title="git文件名太长">git文件名太长</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-git-setting/"
           data-tag="git"
           data-author="pgmanor" >
            <span class="post-title" title="git配置">git配置</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python_tornado_info/"
           data-tag="tornado"
           data-author="pgmanor" >
            <span class="post-title" title="👍Tornado入门这一篇足以">👍Tornado入门这一篇足以</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-maven/"
           data-tag="maven"
           data-author="pgmanor" >
            <span class="post-title" title="maven常用命令和配置">maven常用命令和配置</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-notebook-joplin/"
           data-tag="joplin"
           data-author="pgmanor" >
            <span class="post-title" title="joplin笔记">joplin笔记</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-notebook/"
           data-tag="notebook"
           data-author="pgmanor" >
            <span class="post-title" title="常见笔记软件">常见笔记软件</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2020/12/31/blog-fw-distributed-lock-redis-zk/"
           data-tag="lock,redis,zookeeper"
           data-author="pgmanor" >
            <span class="post-title" title="分布式锁用redis还是zk?">分布式锁用redis还是zk?</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-java-dao-shardingSphere/"
           data-tag="sharding-jdbc"
           data-author="pgmanor" >
            <span class="post-title" title="分库分表中间件-ShardingSphere">分库分表中间件-ShardingSphere</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/12/31/blog-test-rest-assured-in-action/"
           data-tag="rest"
           data-author="pgmanor" >
            <span class="post-title" title="rest-assured实战">rest-assured实战</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 F-----架构 "
           href="/blog/2020/12/31/blog-microservice-why/"
           data-tag="微服务"
           data-author="pgmanor" >
            <span class="post-title" title="一定要使用微服务？">一定要使用微服务？</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-tool-bean-map/"
           data-tag="beanmap"
           data-author="pgmanor" >
            <span class="post-title" title="工具类--bean和map互转">工具类--bean和map互转</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-mysql-common-sql/"
           data-tag="mysql"
           data-author="pgmanor" >
            <span class="post-title" title="mysql常用sql">mysql常用sql</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python-tool-buildin-attr/"
           data-tag="attr"
           data-author="pgmanor" >
            <span class="post-title" title="👍python内置属性(魔法方法)">👍python内置属性(魔法方法)</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-python-tool-obj-dict/"
           data-tag="dict"
           data-author="pgmanor" >
            <span class="post-title" title="python对象与dict互转">python对象与dict互转</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-tool-fastjson-bug/"
           data-tag="fastjson"
           data-author="pgmanor" >
            <span class="post-title" title="Fastjson远程代码高危漏洞">Fastjson远程代码高危漏洞</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 B---大数据 "
           href="/blog/2020/12/31/blog-spark-data-skew/"
           data-tag="spark"
           data-author="pgmanor" >
            <span class="post-title" title="spark数据倾斜及解决方案">spark数据倾斜及解决方案</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 B---大数据 "
           href="/blog/2020/12/31/blog-spark-version-3/"
           data-tag="spark"
           data-author="pgmanor" >
            <span class="post-title" title="spark3.0新特性">spark3.0新特性</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 W-window "
           href="/blog/2020/12/31/blog-tool-windows-cmd/"
           data-tag="windows"
           data-author="pgmanor" >
            <span class="post-title" title="windows常用命令和技巧">windows常用命令和技巧</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 W-window "
           href="/blog/2020/12/31/blog-tool-windows-less-dll/"
           data-tag="dll"
           data-author="pgmanor" >
            <span class="post-title" title="windows缺少dll">windows缺少dll</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/31/blog-tool-youdao-config-edit/"
           data-tag="有道云"
           data-author="pgmanor" >
            <span class="post-title" title="有道云配置修改">有道云配置修改</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 D--数据库 "
           href="/blog/2020/12/31/blog-java-jndi/"
           data-tag="jdni"
           data-author="pgmanor" >
            <span class="post-title" title="JNDI">JNDI</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-online-analysis/"
           data-tag="性能分析"
           data-author="pgmanor" >
            <span class="post-title" title="JAVA线上故障排查全套路">JAVA线上故障排查全套路</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 P-python "
           href="/blog/2020/12/31/blog-tornado-sync-to-async/"
           data-tag="aysnc,tornado"
           data-author="pgmanor" >
            <span class="post-title" title="tornado同步转异步">tornado同步转异步</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 J-----java "
           href="/blog/2020/12/31/blog-java-tool-jackson/"
           data-tag="jackson"
           data-author="pgmanor" >
            <span class="post-title" title="工具类--jackson">工具类--jackson</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/12/31/blog-rest-assured-wiki-info/"
           data-tag="rest"
           data-author="pgmanor" >
            <span class="post-title" title="rest-assured wiki翻译">rest-assured wiki翻译</span>
            <span class="post-date" title="2020-12-31 00:00:00">2020/12/31</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/30/blog-template/"
           data-tag="模板"
           data-author="pgmanor" >
            <span class="post-title" title="hexo博客自定义模板">hexo博客自定义模板</span>
            <span class="post-date" title="2020-12-30 00:00:00">2020/12/30</span>
        </a>
        
        <a  class="博客 T-----工具 "
           href="/blog/2020/12/27/blog-hexo-comments-valine/"
           data-tag="hexo"
           data-author="pgmanor" >
            <span class="post-title" title="hexo扩展评论valine">hexo扩展评论valine</span>
            <span class="post-date" title="2020-12-27 08:59:46">2020/12/27</span>
        </a>
        
        <a  class="博客 D-devops "
           href="/blog/2020/08/15/blog-devops-linux-shell-param/"
           data-tag="linux"
           data-author="pgmanor" >
            <span class="post-title" title="shell 脚本参数解析之getopt和getopts">shell 脚本参数解析之getopt和getopts</span>
            <span class="post-date" title="2020-08-15 00:00:00">2020/08/15</span>
        </a>
        
        <a  class="博客 T-----测试 "
           href="/blog/2020/08/08/blog-test-junit4v5/"
           data-tag="junit"
           data-author="pgmanor" >
            <span class="post-title" title="Junit4和Junit5差异">Junit4和Junit5差异</span>
            <span class="post-date" title="2020-08-08 00:00:00">2020/08/08</span>
        </a>
        
        <a  class="博客 D-devops "
           href="/blog/2020/08/01/blog-devops-linux-command/"
           data-tag="linux"
           data-author="pgmanor" >
            <span class="post-title" title="linux常用命令">linux常用命令</span>
            <span class="post-date" title="2020-08-01 00:00:00">2020/08/01</span>
        </a>
        
        <a  class="博客 D-devops "
           href="/blog/2020/08/01/blog-devops-linux-cmd-adv/"
           data-tag="linux"
           data-author="pgmanor" >
            <span class="post-title" title="linux几个高级命令">linux几个高级命令</span>
            <span class="post-date" title="2020-08-01 00:00:00">2020/08/01</span>
        </a>
        
    </nav>
</div>

    </div>
    <div class="hide-list">
        <div class="semicircle" data-title="切换全屏 快捷键 s">
            <div class="brackets first"><</div>
            <div class="brackets">&gt;</div>
        </div>
    </div>
</aside>
<div class="post">
    <div class="pjax">
        <article id="post-blog/blog-rest-assured-wiki-info" class="article article-type-post" itemscope itemprop="blogPost">
    
        <h1 class="article-title">rest-assured wiki翻译</h1>
    
    <div class="article-meta">
        
        
        <span class="author"><a>pgmanor</a></span>
        
        
        <span class="book">
            
                <a  data-rel="博客">博客</a>/
            
                <a  data-rel="T-----测试">T-----测试</a>
            
        </span>
        
        
        <span class="tag">
            
            <a class="color5">rest</a>
            
        </span>
        
    </div>
    <div class="article-meta">
        
            发布时间 : <time class="date" title='最后更新: 2020-12-15 23:13:04'>2020-12-31 00:00</time>
        
    </div>
    <div class="article-meta">
        
        <span>字数:19.2k</span>
        
        
        <span id="busuanzi_container_page_pv">
            阅读 :<span id="busuanzi_value_page_pv">
                <span class="count-comment">
                    <span class="spinner">
                      <div class="cube1"></div>
                      <div class="cube2"></div>
                    </span>
                </span>
            </span>
        </span>
        
        
        <span class="top-comment" title="跳转至评论区">
            <a href="#comments">
                评论:<span class="count-comment">
                    <span class="spinner">
                      <div class="cube1"></div>
                      <div class="cube2"></div>
                    </span>
                </span>
            </a>
        </span>
        
    </div>
    
    <div class="article-meta">
        <span class="origin">来源:
            <a href="https://github.com/RookieTester/rest-assured-doc/" target="_blank">
                
                rest-assured-wiki翻译
                
            </a>
        </span>
    </div>
    
    <div class="toc-ref">
    
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-静态导入方法"><span class="toc-text">1.静态导入方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-示例"><span class="toc-text">2.示例</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-JSON"><span class="toc-text">2-1.JSON</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-JSON-Schema-validation"><span class="toc-text">2-2.JSON Schema validation</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-XML"><span class="toc-text">2-3.XML</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-复杂的解析和验证"><span class="toc-text">2-4.复杂的解析和验证</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-1-XML示例"><span class="toc-text">2-4-1.XML示例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-4-2-JSON示例"><span class="toc-text">2-4-2.JSON示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-泛型序列化"><span class="toc-text">2-5.泛型序列化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-其它例子"><span class="toc-text">2-6.其它例子</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-关于float和double"><span class="toc-text">3.关于float和double</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-语法关注点"><span class="toc-text">4.语法关注点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-获得响应体信息"><span class="toc-text">5.获得响应体信息</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-从已验证的响应体中提取值"><span class="toc-text">5-1.从已验证的响应体中提取值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-JSON-JsonPath"><span class="toc-text">5-2.JSON(JsonPath)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-XML-XmlPath"><span class="toc-text">5-3.XML(XmlPath)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-4-获取某个路径下的值"><span class="toc-text">5-4.获取某个路径下的值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-Headers-cookies-status"><span class="toc-text">5-5.Headers, cookies, status</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-指定请求数据"><span class="toc-text">6.指定请求数据</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-请求HTTP资源"><span class="toc-text">6-1.请求HTTP资源</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-参数化"><span class="toc-text">6-2.参数化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-多值参数"><span class="toc-text">6-3.多值参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-4-无值参数"><span class="toc-text">6-4.无值参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-5-路径参数"><span class="toc-text">6-5.路径参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-6-Cookie"><span class="toc-text">6-6.Cookie</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-7-Header"><span class="toc-text">6-7.Header</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-8-Content-Type"><span class="toc-text">6-8.Content Type</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-9-请求正文"><span class="toc-text">6-9.请求正文</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-验证响应数据"><span class="toc-text">7.验证响应数据</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-响应体"><span class="toc-text">7-1.响应体</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-Cookie"><span class="toc-text">7-2.Cookie</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-3-状态码"><span class="toc-text">7-3.状态码</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-4-Header"><span class="toc-text">7-4.Header</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-5-Content-Type"><span class="toc-text">7-5.Content-Type</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-6-内容全匹配"><span class="toc-text">7-6.内容全匹配</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-7-关联类型验证"><span class="toc-text">7-7.关联类型验证</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-8-计算响应时间"><span class="toc-text">7-8.计算响应时间</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-认证"><span class="toc-text">8.认证</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-1-基本认证"><span class="toc-text">8-1.基本认证</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-1-抢占式"><span class="toc-text">8-1-1.抢占式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-2-受质询的基本认证"><span class="toc-text">8-1-2.受质询的基本认证</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-摘要认证"><span class="toc-text">8-2.摘要认证</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-表单认证"><span class="toc-text">8-3.表单认证</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-1-CSRF"><span class="toc-text">8-3-1.CSRF</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-2-附加字段"><span class="toc-text">8-3-2.附加字段</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-4-OAut"><span class="toc-text">8-4.OAut</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-1-OAuth-1"><span class="toc-text">8-4-1.OAuth 1</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-2-OAuth-2"><span class="toc-text">8-4-2.OAuth 2</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-5-自定义身份验证"><span class="toc-text">8-5.自定义身份验证</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-Multi-part表单数据"><span class="toc-text">9.Multi-part表单数据</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-对象映射"><span class="toc-text">10.对象映射</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#10-1-序列化"><span class="toc-text">10-1.序列化</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-1-基于Content-Type的序列化"><span class="toc-text">10-1-1.基于Content-Type的序列化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-2-由HashMap创建JSON"><span class="toc-text">10-1-2.由HashMap创建JSON</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-3-使用显式序列化器"><span class="toc-text">10-1-3.使用显式序列化器</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-2-反序列化"><span class="toc-text">10-2.反序列化</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-1-基于Content-Type的反序列化"><span class="toc-text">10-2-1.基于Content-Type的反序列化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-2-自定义类型content-type反序列化"><span class="toc-text">10-2-2.自定义类型content-type反序列化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-3-使用显式反序列化器"><span class="toc-text">10-2-3.使用显式反序列化器</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-3-配置"><span class="toc-text">10-3.配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-4-自定义"><span class="toc-text">10-4.自定义</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11-解析器"><span class="toc-text">11.解析器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#11-1-自定义解析器"><span class="toc-text">11-1.自定义解析器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#11-2-默认解析器"><span class="toc-text">11-2.默认解析器</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12-默认值"><span class="toc-text">12.默认值</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#13-模式复用"><span class="toc-text">13.模式复用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14-过滤器"><span class="toc-text">14.过滤器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#14-1-Ordered-Filters"><span class="toc-text">14-1.Ordered Filters</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#14-2-Response-Builder"><span class="toc-text">14-2.Response Builder</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#15-日志"><span class="toc-text">15.日志</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#15-1-请求日志"><span class="toc-text">15-1.请求日志</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-2-响应日志"><span class="toc-text">15-2.响应日志</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-3-认证失败日志"><span class="toc-text">15-3.认证失败日志</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-4-黑名单日志"><span class="toc-text">15-4.黑名单日志</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#16-根路径"><span class="toc-text">16.根路径</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#16-1-路径参数"><span class="toc-text">16-1.路径参数</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#17-Session支持"><span class="toc-text">17.Session支持</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#17-1-Session过滤器"><span class="toc-text">17-1.Session过滤器</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#18-SSL"><span class="toc-text">18.SSL</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#18-1-SSL无效主机名"><span class="toc-text">18-1.SSL无效主机名</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#19-URL编码"><span class="toc-text">19.URL编码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#20-代理配置"><span class="toc-text">20.代理配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#20-1-静态代理配置"><span class="toc-text">20-1.静态代理配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#20-2-请求规范代理配置"><span class="toc-text">20-2.请求规范代理配置</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#21-详细配置"><span class="toc-text">21.详细配置</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#21-1-编码配置"><span class="toc-text">21-1.编码配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-2-解码配置"><span class="toc-text">21-2.解码配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-3-Session配置"><span class="toc-text">21-3.Session配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-3-重定向-DSL"><span class="toc-text">21-3.重定向 DSL</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-4-网络连接配置"><span class="toc-text">21-4.网络连接配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-5-Json-Config"><span class="toc-text">21-5.Json Config</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-6-HTTP-Client配置"><span class="toc-text">21-6.HTTP Client配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-7-SSL配置"><span class="toc-text">21-7.SSL配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-8-参数配置"><span class="toc-text">21-8.参数配置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#21-10-失败配置"><span class="toc-text">21-10.失败配置</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#22-Spring-Mock-Mvc-模块"><span class="toc-text">22.Spring Mock Mvc 模块</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#22-1-Bootstrapping-RestAssuredMockMvc"><span class="toc-text">22-1.Bootstrapping RestAssuredMockMvc</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-2-异步请求"><span class="toc-text">22-2.异步请求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-3-添加请求后处理器"><span class="toc-text">22-3.添加请求后处理器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-4-添加结果处理器"><span class="toc-text">22-4.添加结果处理器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-5-使用结果匹配器"><span class="toc-text">22-5.使用结果匹配器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-5-拦截器"><span class="toc-text">22-5.拦截器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-6-Specifications"><span class="toc-text">22-6.Specifications</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-7-重置-RestAssuredMockMvc"><span class="toc-text">22-7.重置 RestAssuredMockMvc</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#22-8-Spring-MVC认证"><span class="toc-text">22-8.Spring MVC认证</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#22-8-1-使用-Spring-Security测试"><span class="toc-text">22-8-1.使用 Spring Security测试</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#22-8-2-注入一个用户"><span class="toc-text">22-8-2.注入一个用户</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#23-Scala支持"><span class="toc-text">23.Scala支持</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#24-Kotlin支持"><span class="toc-text">24.Kotlin支持</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#25-更多信息"><span class="toc-text">25.更多信息</span></a></li></ol>
    
<style>
    .left-col .switch-btn,
    .left-col .switch-area {
        display: none;
    }
    .toc-level-4 i,
    .toc-level-4 ol {
        display: none !important;
    }
</style>
</div>
    
    <div class="article-entry" itemprop="articleBody">
      
        <blockquote>
<p>本文是基于官网的wiki翻译，首先感谢翻译者辛苦了(我复制过来排了个版，都花了近1小时)。官网最新版比翻译时版本多了些内容。</p>
</blockquote>
<ul>
<li><a href="http://rest-assured.io/" target="_blank" rel="noopener">rest-assured官网</a></li>
<li><a href="https://github.com/rest-assured/rest-assured/wiki/Usage" target="_blank" rel="noopener">rest-assured-wiki</a></li>
</ul>
<p>rest-assured是一个测试 RESTful Web Services的Java类库。<br>可以使用Rest-Assured编写高度自定义化的HTTP请求用来测试各种各样Restful服务组合的业务实现。<br>它支持发起POST,GET,PUT,DELETE,OPTIONS,PATCH和HEAD请求，并且可以用来验证和校对这些请求的响应信息。</p>
<p>REST Assured是一个可以简化HTTP Builder顶层 基于REST服务的测试过程的Java <strong>DSL</strong>（针对某一领域，具有受限表达性的一种计算机程序设计语言）。它支持发起POST,GET,PUT,DELETE,OPTIONS,PATCH和HEAD请求，并且可以用来验证和校对这些请求的响应信息。</p>
<h2 id="1-静态导入方法"><a href="#1-静态导入方法" class="headerlink" title="1.静态导入方法"></a>1.静态导入方法</h2><p>推荐大家从以下的类中静态导入方法，以提高使用rest-assured的效率。</p>
<pre><code class="java">io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*</code></pre>
<p>如果您想使用<a href="http://json-schema.org/" target="_blank" rel="noopener">Json Schema</a> validation 还应该静态导入这些方法： </p>
<pre><code class="java">io.restassured.module.jsv.JsonSchemaValidator.*</code></pre>
<p>更多使用方法参阅 <a href="#json-schema-validation">Json Schema Validation</a> 。</p>
<p>如果您正在使用SpringMVC，你可以使用<a href="#spring-mock-mvc-module">spring-mock-mvc</a> 模型的Rest Assured DSL来对Spring的controller层进行单元测试。为此需要从<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/RestAssuredMockMvc.html" target="_blank" rel="noopener">RestAssuredMockMvc</a>静态导入这些方法，而不是<code>io.restassured.RestAssured</code>:</p>
<pre><code class="java">io.restassured.module.mockmvc.RestAssuredMockMvc.*</code></pre>
<h2 id="2-示例"><a href="#2-示例" class="headerlink" title="2.示例"></a>2.示例</h2><h3 id="2-1-JSON"><a href="#2-1-JSON" class="headerlink" title="2-1.JSON"></a>2-1.JSON</h3><p>假设某个get请求 (to <a href="http://localhost:8080/lotto" target="_blank" rel="noopener">http://localhost:8080/lotto</a>) 返回JSON如下:</p>
<pre><code class="json">{
&quot;lotto&quot;:{
 &quot;lottoId&quot;:5,
 &quot;winning-numbers&quot;:[2,45,34,23,7,5,3],
 &quot;winners&quot;:[{
   &quot;winnerId&quot;:23,
   &quot;numbers&quot;:[2,45,34,23,3,5]
 },{
   &quot;winnerId&quot;:54,
   &quot;numbers&quot;:[52,3,12,11,18,22]
 }]
}
}</code></pre>
<p>REST assured可以帮您轻松地进行get请求并对响应信息进行处理。举个例子，如果想要判断lottoId的值是否等于5，你可以这样做：</p>
<pre><code class="java">get(&quot;/lotto&quot;).then().body(&quot;lotto.lottoId&quot;, equalTo(5));</code></pre>
<p>又或许您想要检查winnerId的取值<strong>包括</strong>23和54：</p>
<pre><code class="java">get(&quot;/lotto&quot;).then().body(&quot;lotto.winners.winnerId&quot;, hasItems(23, 54));</code></pre>
<p>注意: <code>equalTo</code> 和 <code>hasItems</code> 是 Hamcrest matchers的方法，所以需要静态导入 <code>org.hamcrest.Matchers</code>。</p>
<p>注意这里的”json path”语法使用的是<a href='http://groovy-lang.org/processing-xml.html#_gpath' target="_blank" rel="noopener">Groovy的GPath</a>标注法，不要和Jayway的<a href='https://github.com/jayway/JsonPath' target="_blank" rel="noopener">JsonPath</a>语法混淆。</p>
<p><strong>以BigDecimal返回float和double类型</strong></p>
<p>（译者注：Java在java.math包中提供的API类BigDecimal，用来对超过16位有效位的数进行精确的运算）</p>
<p>您可以对rest-assured和JsonPath进行配置，使之以BigDecimal返回json里的数值类型数据，而不是float或者double。可以参考下面json文本：</p>
<pre><code class="json">{

    &quot;price&quot;:12.12 

}</code></pre>
<p>默认情况下您验证price字段是否等于float类型的12.12像这样：</p>
<pre><code class="java">get(&quot;/price&quot;).then().body(&quot;price&quot;, is(12.12f));</code></pre>
<p>但是如果想用rest-assured的JsonConfig来配置返回的所有的json数值都为BigDecimal类型：</p>
<pre><code class="java">given().
        config(RestAssured.config().jsonConfig(jsonConfig().numberReturnType(BIG_DECIMAL))).
when().
        get(&quot;/price&quot;).
then().
        body(&quot;price&quot;, is(new BigDecimal(12.12));</code></pre>
<h3 id="2-2-JSON-Schema-validation"><a href="#2-2-JSON-Schema-validation" class="headerlink" title="2-2.JSON Schema validation"></a>2-2.JSON Schema validation</h3><p>自从 <code>2.1.0</code> 版本rest-assured开始支持<a href="http://json-schema.org/" target="_blank" rel="noopener">Json Schema</a> validation. 举个例子，在classpath中放置以下的schema文件（译者注：idea的话可以放在resources目录下），products-schema.json:</p>
<pre><code class="json">{
    &quot;$schema&quot;: &quot;http://json-schema.org/draft-04/schema#&quot;,
    &quot;title&quot;: &quot;Product set&quot;,
    &quot;type&quot;: &quot;array&quot;,
    &quot;items&quot;: {
        &quot;title&quot;: &quot;Product&quot;,
        &quot;type&quot;: &quot;object&quot;,
        &quot;properties&quot;: {
            &quot;id&quot;: {
                &quot;description&quot;: &quot;The unique identifier for a product&quot;,
                &quot;type&quot;: &quot;number&quot;
            },
            &quot;name&quot;: {
                &quot;type&quot;: &quot;string&quot;
            },
            &quot;price&quot;: {
                &quot;type&quot;: &quot;number&quot;,
                &quot;minimum&quot;: 0,
                &quot;exclusiveMinimum&quot;: true
            },
            &quot;tags&quot;: {
                &quot;type&quot;: &quot;array&quot;,
                &quot;items&quot;: {
                    &quot;type&quot;: &quot;string&quot;
                },
                &quot;minItems&quot;: 1,
                &quot;uniqueItems&quot;: true
            },
            &quot;dimensions&quot;: {
                &quot;type&quot;: &quot;object&quot;,
                &quot;properties&quot;: {
                    &quot;length&quot;: {&quot;type&quot;: &quot;number&quot;},
                    &quot;width&quot;: {&quot;type&quot;: &quot;number&quot;},
                    &quot;height&quot;: {&quot;type&quot;: &quot;number&quot;}
                },
                &quot;required&quot;: [&quot;length&quot;, &quot;width&quot;, &quot;height&quot;]
            },
            &quot;warehouseLocation&quot;: {
                &quot;description&quot;: &quot;Coordinates of the warehouse with the product&quot;,
                &quot;$ref&quot;: &quot;http://json-schema.org/geo&quot;
            }
        },
        &quot;required&quot;: [&quot;id&quot;, &quot;name&quot;, &quot;price&quot;]
    }
}</code></pre>
<p>您可以使用这个schema验证(<code>/products</code>)这个请求是否符合规范：</p>
<pre><code class="java">get(&quot;/products&quot;).then().assertThat().body(matchesJsonSchemaInClasspath(&quot;products-schema.json&quot;));</code></pre>
<p><code>matchesJsonSchemaInClasspath</code> 静态导入自 <code>io.restassured.module.jsv.JsonSchemaValidator</code> 并且我们推荐从这个类中静态导入所有的方法。然而为了使用它需要依赖于<code>json-schema-validator</code> module 或者从这个网页 <a href="http://dl.bintray.com/johanhaleby/generic/json-schema-validator-3.0.1-dist.zip" target="_blank" rel="noopener">下载</a> 它， 又或者通过maven添加下面的依赖:</p>
<pre><code class="xml">&lt;dependency&gt;
    &lt;groupId&gt;io.rest-assured&lt;/groupId&gt;
    &lt;artifactId&gt;json-schema-validator&lt;/artifactId&gt;
    &lt;version&gt;3.0.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p><strong>JSON Schema Validation设置项</strong></p>
<p>rest-assured的<code>json-schema-validator</code> module使用Francis Galiegue的<a href="https://github.com/fge/json-schema-validator" target="_blank" rel="noopener">json-schema-validator</a> (<code>fge</code>) 库来进行验证。 如果您想配置使用基础<code>fge</code>库，你可以像下面例子中：</p>
<pre><code class="java">// Given
JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.newBuilder().setValidationConfiguration(ValidationConfiguration.newBuilder().setDefaultVersion(DRAFTV4).freeze()).freeze();

// When
get(&quot;/products&quot;).then().assertThat().body(matchesJsonSchemaInClasspath(&quot;products-schema.json&quot;).using(jsonSchemaFactory));</code></pre>
<p>using方法允许您进入<code>jsonSchemaFactory</code>的实例，rest-assured在验证期间也会进行此操作。这种方式允许我们对验证进行细粒度的配置。</p>
<p><code>fge</code>库也允许验证状态是 <code>checked</code>或者<code>unchecked</code>（译者注：表示不懂）。默认情况，rest-assured使用<code>checked</code>验证，但是如果你想要改变这种方式，您可以提供一个matcher的<a href="http://static.javadoc.io/io.restassured/json-schema-validator/3.0.1/io/restassured/module/jsv/JsonSchemaValidatorSettings.html" target="_blank" rel="noopener">JsonSchemaValidatorSettings</a>实例。举个例子：</p>
<pre><code class="java">get(&quot;/products&quot;).then().assertThat().body(matchesJsonSchemaInClasspath(&quot;products-schema.json&quot;).using(settings().with().checkedValidation(false)));</code></pre>
<p>这些<code>settings</code>方法静态导入自 <a href="http://static.javadoc.io/io.restassured/json-schema-validator/3.0.1/io/restassured/module/jsv/JsonSchemaValidatorSettings.html" target="_blank" rel="noopener">JsonSchemaValidatorSettings</a>类。</p>
<p><strong>Json Schema Validation的静态配置</strong><br>现在想象下您总是使用<code>unchecked</code>验证，并且设置默认的json schema版本为3。与其每次都在代码里进行设置，不如静态地进行定义设置。举个例子：</p>
<pre><code class="java">JsonSchemaValidator.settings = settings().with().jsonSchemaFactory(
        JsonSchemaFactory.newBuilder().setValidationConfiguration(ValidationConfiguration.newBuilder().setDefaultVersion(DRAFTV3).freeze()).freeze()).
        and().with().checkedValidation(false);

get(&quot;/products&quot;).then().assertThat().body(matchesJsonSchemaInClasspath(&quot;products-schema.json&quot;));</code></pre>
<p>现在任意一个由<a href="http://static.javadoc.io/io.restassured/json-schema-validator/3.0.1/io/restassured/module/jsv/JsonSchemaValidatorSettings.html" target="_blank" rel="noopener">JsonSchemaValidator</a>导入的<code>matcher</code>都会使用<code>DRAFTV3</code>作为默认版本并且unchecked validation。</p>
<p>想要重置<code>JsonSchemaValidator</code>到默认设置仅仅需要调用<code>reset</code>方法：</p>
<pre><code class="java">JsonSchemaValidator.reset();</code></pre>
<p><strong>不使用rest-assured的Json Schema Validation</strong><br>您也可以在不依赖rest-assured的情况下使用<code>json-schema-validator</code> module。如想要把json文本表示为<code>String</code>类型的字符串，可以这样做：</p>
<pre><code class="java">import org.junit.Test;
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
import static org.hamcrest.MatcherAssert.assertThat;

public class JsonSchemaValidatorWithoutRestAssuredTest {


    @Test 
    public void validates_schema_in_classpath() {
        // Given
        String json = ... // Greeting response

        // Then
        assertThat(json, matchesJsonSchemaInClasspath(&quot;greeting-schema.json&quot;));
    }
}</code></pre>
<p>更多信息请参阅<a href="https://github.com/rest-assured/rest-assured/wiki/GattingStarted" target="_blank" rel="noopener">新手入门</a>。</p>
<p><strong>匿名式的JSON根节点验证</strong></p>
<p>一个JSON文本并不总是有一个命名好的根属性。这里有个验证这种JSON的例子：</p>
<pre><code class="json">[1, 2, 3]</code></pre>
<p>一个匿名的JSON根属性可以通过使用<code>$</code>或者空字符串作为路径来识别。举个例子，通过访问<code>http://localhost:8080/json</code>这个地址可以获得一个JSON文本，我们可以使用rest-assured验证：</p>
<pre><code class="java">when().
     get(&quot;/json&quot;).
then().
     body(&quot;$&quot;, hasItems(1, 2, 3)); // An empty string &quot;&quot; would work as well</code></pre>
<h3 id="2-3-XML"><a href="#2-3-XML" class="headerlink" title="2-3.XML"></a>2-3.XML</h3><p>XML可以一种通过简单的方式解析。假设一个POST请求<code>http://localhost:8080/greetXML</code>返回：</p>
<pre><code class="xml">&lt;greeting&gt;
   &lt;firstName&gt;{params(&quot;firstName&quot;)}&lt;/firstName&gt;
   &lt;lastName&gt;{params(&quot;lastName&quot;)}&lt;/lastName&gt;
&lt;/greeting&gt;</code></pre>
<p>换言之，它在请求中返还了一个基于firstname和lastname请求参数的greeting节点。您可以通过rest-assured轻易地展现和解析这个例子：</p>
<pre><code class="java">given().
         parameters(&quot;firstName&quot;, &quot;John&quot;, &quot;lastName&quot;, &quot;Doe&quot;).
when().
         post(&quot;/greetXML&quot;).
then().
         body(&quot;greeting.firstName&quot;, equalTo(&quot;John&quot;)).</code></pre>
<p>如果您想同时解析firstname和lastname可以这样做：</p>
<pre><code class="java">given().
         parameters(&quot;firstName&quot;, &quot;John&quot;, &quot;lastName&quot;, &quot;Doe&quot;).
when().
         post(&quot;/greetXML&quot;).
then().
         body(&quot;greeting.firstName&quot;, equalTo(&quot;John&quot;)).
         body(&quot;greeting.lastName&quot;, equalTo(&quot;Doe&quot;));</code></pre>
<p>或者稍微简短些：</p>
<pre><code class="java">with().parameters(&quot;firstName&quot;, &quot;John&quot;, &quot;lastName&quot;, &quot;Doe&quot;).when().post(&quot;/greetXML&quot;).then().body(&quot;greeting.firstName&quot;, equalTo(&quot;John&quot;), &quot;greeting.lastName&quot;, equalTo(&quot;Doe&quot;));</code></pre>
<p>看<a href="http://groovy-lang.org/processing-xml.html#_gpath" target="_blank" rel="noopener">这里</a> 的链接获取有关语法的更多信息(它遵循 Groovy的 <a href="http://groovy-lang.org/processing-xml.html#_gpath" target="_blank" rel="noopener">GPath</a> 语法).</p>
<p><strong>XML命名空间</strong><br>考虑到您需要使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/XmlConfig.html" target="_blank" rel="noopener">io.restassured.config.XmlConfig</a>声明一个命名空间。举个例子，有一个位于<code>http://localhost:8080</code>的资源<code>namespace-example</code>，返回如下的XML：</p>
<pre><code class="xml">&lt;foo xmlns:ns=&quot;http://localhost/&quot;&gt;
  &lt;bar&gt;sudo &lt;/bar&gt;
  &lt;ns:bar&gt;make me a sandwich!&lt;/ns:bar&gt;
&lt;/foo&gt;</code></pre>
<p>可以然后声明<code>http://localhost/</code>这个URI并且验证其响应：</p>
<pre><code class="java">given().
        config(RestAssured.config().xmlConfig(xmlConfig().declareNamespace(&quot;test&quot;, &quot;http://localhost/&quot;))).
when().
         get(&quot;/namespace-example&quot;).
then().
         body(&quot;foo.bar.text()&quot;, equalTo(&quot;sudo make me a sandwich!&quot;)).
         body(&quot;:foo.:bar.text()&quot;, equalTo(&quot;sudo &quot;)).
         body(&quot;foo.test:bar.text()&quot;, equalTo(&quot;make me a sandwich!&quot;));</code></pre>
<p>这个路径语法遵循Groovy的XmlSlurper语法。注意直到2.6.0的路径语法都<em>不</em>遵循Groovy的XmlSlurper语法。请看<a href="https://github.com/rest-assured/rest-assured/wiki/ReleaseNotes26#non-backward-compatible-changes" target="_blank" rel="noopener">release notes</a>可以获知2.6.0之前的版本语法是怎样的。</p>
<p><strong>XPath</strong></p>
<p>您也可以使用x-path来解析XML响应。举个例子：</p>
<pre><code class="java">given().parameters(&quot;firstName&quot;, &quot;John&quot;, &quot;lastName&quot;, &quot;Doe&quot;).when().post(&quot;/greetXML&quot;).then().body(hasXPath(&quot;/greeting/firstName&quot;, containsString(&quot;Jo&quot;)));</code></pre>
<p>或者</p>
<pre><code class="java">given().parameters(&quot;firstName&quot;, &quot;John&quot;, &quot;lastName&quot;, &quot;Doe&quot;).post(&quot;/greetXML&quot;).then().body(hasXPath(&quot;/greeting/firstName[text()=&#39;John&#39;]&quot;));</code></pre>
<p>在XPath表达式中使用命名空间，你需要在配置中启用这些选项：</p>
<pre><code class="java">given().
        config(RestAssured.config().xmlConfig(xmlConfig().with().namespaceAware(true))).
when().
         get(&quot;/package-db-xml&quot;).
then().
         body(hasXPath(&quot;/db:package-database&quot;, namespaceContext));</code></pre>
<p><code>namespaceContext</code> 是一个<a href="http://docs.oracle.com/javase/7/docs/api/javax/xml/namespace/NamespaceContext.html" target="_blank" rel="noopener">javax.xml.namespace.NamespaceContext</a>的实例 。</p>
<p><strong>Schema和DTD</strong></p>
<p>XML响应体也可以验证为一个XML Schema (XSD)或DTD.</p>
<p><strong>XSD 例子</strong></p>
<pre><code class="java">get(&quot;/carRecords&quot;).then().assertThat().body(matchesXsd(xsd));</code></pre>
<p><strong>DTD 例子</strong></p>
<pre><code class="java">get(&quot;/videos&quot;).then().assertThat().body(matchesDtd(dtd));</code></pre>
</p>
<code>matchesXsd</code>和<code>matchesDtd</code>方法在Hamcrest matchers里，你可以从<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/matcher/RestAssuredMatchers.html" target="_blank" rel="noopener">io.restassured.matcher.RestAssuredMatchers</a><br>
导入。</p>

<h3 id="2-4-复杂的解析和验证"><a href="#2-4-复杂的解析和验证" class="headerlink" title="2-4.复杂的解析和验证"></a>2-4.复杂的解析和验证</h3><p>这正是rest-assured闪光点所在！由于rest-assured实现了Groovy，它可以从Groovy集合的API的优点中获益。让我们从下面的Groovy例子中开始探索：</p>
<pre><code class="groovy">def words = [&#39;ant&#39;, &#39;buffalo&#39;, &#39;cat&#39;, &#39;dinosaur&#39;]
def wordsWithSizeGreaterThanFour = words.findAll { it.length() &gt; 4 }</code></pre>
<p>在第一行，我们简单地定义了一个包含一些单词的列表，不过第二行更加有趣。<br>这里我们检索了列表里的所有长度大于4的单词，通过一个叫做findAll的Groovy闭包。<br>这个闭包有一个内部变量<code>it</code>，代表着列表中当前的元素。<br>结果是一个新的列表， <code>wordsWithSizeGreaterThanFour</code>,包含<code>buffalo</code> and <code>dinosaur</code>。</p>
<p>这里还有一些其它的有趣的方法，我们也可以使用在Groovy集合中：</p>
<ul>
<li><code>find</code> – 找到第一个匹配闭包谓词（closure predicate）的元素</li>
<li><code>collect</code> – 收集在集合里的每个元素都调用的闭包返回值（collect the return value of calling a closure on each item in a collection）</li>
<li><code>sum</code> – 对集合里的元素进行求和</li>
<li><code>max</code>/<code>min</code> – 返回集合里的最大值/最小值</li>
</ul>
<p>所以我们如何在使用rest-assured验证XML和JSON响应时利用这些优点？</p>
<h4 id="2-4-1-XML示例"><a href="#2-4-1-XML示例" class="headerlink" title="2-4-1.XML示例"></a>2-4-1.XML示例</h4><p>比方说我们有个资源<code>http://localhost:8080/shopping</code>返回如下的XML：</p>
<pre><code class="xml">&lt;shopping&gt;
      &lt;category type=&quot;groceries&quot;&gt;
        &lt;item&gt;Chocolate&lt;/item&gt;
        &lt;item&gt;Coffee&lt;/item&gt;
      &lt;/category&gt;
      &lt;category type=&quot;supplies&quot;&gt;
        &lt;item&gt;Paper&lt;/item&gt;
        &lt;item quantity=&quot;4&quot;&gt;Pens&lt;/item&gt;
      &lt;/category&gt;
      &lt;category type=&quot;present&quot;&gt;
        &lt;item when=&quot;Aug 10&quot;&gt;Kathryn&#39;s Birthday&lt;/item&gt;
      &lt;/category&gt;
&lt;/shopping&gt;</code></pre>
<p>又比如我们想写一个测试来检验类型为groceries的category节点有Chocolate和Coffee这两个项目。在rest-assured可以这样做：</p>
<pre><code class="java">when().
       get(&quot;/shopping&quot;).
then().
       body(&quot;shopping.category.find { it.@type == &#39;groceries&#39; }.item&quot;, hasItems(&quot;Chocolate&quot;, &quot;Coffee&quot;));</code></pre>
<p>这里发生了什么事？首先使用XML路径<code>shopping.category</code>获取了所有categoriy的一个列表。在这个列表中我们又调用了一个方法，<code>find</code>，来返回有<code>type</code>这个属性且该属性值为<code>groceries</code>的单个category节点。</p>
<p>在这个category上我们接下来继续收集所有相关联的项目（item）。</p>
<p>由于这里与category相关联的项目不止一个，所以会返回一个列表。接下来我们通过Hamcrest matcher的<code>hasItems</code>方法来解析它。</p>
<p>但是如果我们想取得一些项目（item）但又不想进行断言验证该怎么办？您可以参考<a href="http://static.javadoc.io/io.restassured/xml-path/3.0.1/io/restassured/path/xml/XmlPath.html" target="_blank" rel="noopener">XmlPath</a>:</p>
<pre><code class="java">// Get the response body as a String
String response = get(&quot;/shopping&quot;).asString();
// And get the groceries from the response. &quot;from&quot; is statically imported from the XmlPath class
List&lt;String&gt; groceries = from(response).getList(&quot;shopping.category.find { it.@type == &#39;groceries&#39; }.item&quot;);</code></pre>
<p>如果groceries是您对这个响应里唯一的关注点，也可以使用一个<a href="#single-path">捷径</a>:</p>
<pre><code class="java">// Get the response body as a String
List&lt;String&gt; groceries = get(&quot;/shopping&quot;).path(&quot;shopping.category.find { it.@type == &#39;groceries&#39; }.item&quot;);</code></pre>
<p><strong>深度优先搜索</strong></p>
<p>实际上之前的例子我们还可以继续简化：</p>
<pre><code class="java">when().
       get(&quot;/shopping&quot;).
then().
       body(&quot;**.find { it.@type == &#39;groceries&#39; }&quot;, hasItems(&quot;Chocolate&quot;, &quot;Coffee&quot;));</code></pre>
<p><code>**</code>是一种在XML文件中做深度优先搜索的捷径。</p>
<p>我们搜索第一个<code>type</code>属性值等于”groceries”的节点。注意我们没有在”item”这个XML路径结束。</p>
<p>原因是在category节点返回一个列表的项目值时，自动调用了<code>toString()</code>这个方法（译者注：这两句有啥因果关系我没搞懂）。</p>
<h4 id="2-4-2-JSON示例"><a href="#2-4-2-JSON示例" class="headerlink" title="2-4-2.JSON示例"></a>2-4-2.JSON示例</h4><p>假设<code>http://localhost:8080/store</code>返回如下的JSON：</p>
<pre><code class="javascript">{  
   &quot;store&quot;:{  
      &quot;book&quot;:[  
         {  
            &quot;author&quot;:&quot;Nigel Rees&quot;,
            &quot;category&quot;:&quot;reference&quot;,
            &quot;price&quot;:8.95,
            &quot;title&quot;:&quot;Sayings of the Century&quot;
         },
         {  
            &quot;author&quot;:&quot;Evelyn Waugh&quot;,
            &quot;category&quot;:&quot;fiction&quot;,
            &quot;price&quot;:12.99,
            &quot;title&quot;:&quot;Sword of Honour&quot;
         },
         {  
            &quot;author&quot;:&quot;Herman Melville&quot;,
            &quot;category&quot;:&quot;fiction&quot;,
            &quot;isbn&quot;:&quot;0-553-21311-3&quot;,
            &quot;price&quot;:8.99,
            &quot;title&quot;:&quot;Moby Dick&quot;
         },
         {  
            &quot;author&quot;:&quot;J. R. R. Tolkien&quot;,
            &quot;category&quot;:&quot;fiction&quot;,
            &quot;isbn&quot;:&quot;0-395-19395-8&quot;,
            &quot;price&quot;:22.99,
            &quot;title&quot;:&quot;The Lord of the Rings&quot;
         }
      ]
   }
}</code></pre>
<p><strong>例1</strong><br>在本例中我们发起一个请求”/store”，并且做了一个断言：搜集满足price字段值小于10的所有book数组里的title字段，得到了”Sayings of the Century”和”Moby Dick”这两个结果：</p>
<pre><code class="java">when().
       get(&quot;/store&quot;).
then().
       body(&quot;store.book.findAll { it.price &lt; 10 }.title&quot;, hasItems(&quot;Sayings of the Century&quot;, &quot;Moby Dick&quot;));</code></pre>
<p>就像上面XML的例子，我们使用闭包获取所有price字段值低于10的book数组，并且返回相应的title字段值集合。</p>
<p>然后使用<code>hasItems</code>这个匹配器来断言得到我们预期的结果。使用<a href="http://static.javadoc.io/io.restassured/json-path/3.0.1/io/restassured/path/json/JsonPath.html" target="_blank" rel="noopener">JsonPath</a> 我们可以用下面的方法替代：</p>
<pre><code class="java">// Get the response body as a String
String response = get(&quot;/store&quot;).asString();
// And get all books with price &lt; 10 from the response. &quot;from&quot; is statically imported from the JsonPath class
List&lt;String&gt; bookTitles = from(response).getList(&quot;store.book.findAll { it.price &lt; 10 }.title&quot;);</code></pre>
<p><strong>例2</strong><br>考虑下该如何断言所有author字段值长度总和是否大于50的结果。</p>
<p>这是个挺难以回答的问题，也正展示了闭包和Groovy集合的强大之处。在rest-assured里可以：</p>
<pre><code class="java"> when().
        get(&quot;/store&quot;);
 then().
        body(&quot;store.book.author.collect { it.length() }.sum()&quot;, greaterThan(50));</code></pre>
<p>首先我们通过(<code>store.book.author</code>)得到了所有的author字段值，然后使用闭包里的方法<code>{ it.length() }</code>解析这个集合。</p>
<p>它所做的是对列表里的每一个author字段执行一次<code>length()</code>方法，然后返回一个新的列表。在这个列表中，我们再调用<code>sum()</code>方法来求得字符长度的总和。</p>
<p>最终的结果是53，并且我们使用<code>greaterThan</code>匹配器的断言结果是大于50 。<br>但是实际上可以继续简化这种写法。可以再次参考”<a href="#例3---复杂的解析">words</a>“这个例子</p>
<pre><code class="groovy">def words = [&#39;ant&#39;, &#39;buffalo&#39;, &#39;cat&#39;, &#39;dinosaur&#39;]</code></pre>
<p>Groovy有一个便利的方法可以遍历列表中的所有元素，使用<code>*</code>来调用。举个例子：</p>
<pre><code class="groovy">def words = [&#39;ant&#39;, &#39;buffalo&#39;, &#39;cat&#39;, &#39;dinosaur&#39;]
assert [3, 6, 3, 8] == words*.length()</code></pre>
<p>Groovy返回了一个新的包含words中每个字段字符长度的列表。我们也可以把rest-assured中的这个语法用在author列表中：</p>
<pre><code class="java">when().
       get(&quot;/store&quot;);
then().
       body(&quot;store.book.author*.length().sum()&quot;, greaterThan(50)).</code></pre>
<p>当然我们可以使用<a href="http://static.javadoc.io/io.restassured/json-path/3.0.1/io/restassured/path/json/JsonPath.html" target="_blank" rel="noopener">JsonPath</a>来获取这个结果：</p>
<pre><code class="java">// Get the response body as a string
String response = get(&quot;/store&quot;).asString();
// Get the sum of all author length&#39;s as an int. &quot;from&quot; is again statically imported from the JsonPath class
int sumOfAllAuthorLengths = from(response).getInt(&quot;store.book.author*.length().sum()&quot;);
// We can also assert that the sum is equal to 53 as expected.
assertThat(sumOfAllAuthorLengths, is(53));</code></pre>
<h3 id="2-5-泛型序列化"><a href="#2-5-泛型序列化" class="headerlink" title="2-5.泛型序列化"></a>2-5.泛型序列化</h3><p>REST Assured 3.3.0 introduced the io.restassured.mapper.TypeRef class that allows you to de-serialize the response to a container with a generic type. For example let’s say that you have a service that returns the following JSON for a GET request to /products:</p>
<pre><code class="json">[
          {
              &quot;id&quot;: 2,
              &quot;name&quot;: &quot;An ice sculpture&quot;,
              &quot;price&quot;: 12.50,
              &quot;tags&quot;: [&quot;cold&quot;, &quot;ice&quot;],
              &quot;dimensions&quot;: {
                  &quot;length&quot;: 7.0,
                  &quot;width&quot;: 12.0,
                  &quot;height&quot;: 9.5
              },
              &quot;warehouseLocation&quot;: {
                  &quot;latitude&quot;: -78.75,
                  &quot;longitude&quot;: 20.4
              }
          },
          {
              &quot;id&quot;: 3,
              &quot;name&quot;: &quot;A blue mouse&quot;,
              &quot;price&quot;: 25.50,
                  &quot;dimensions&quot;: {
                  &quot;length&quot;: 3.1,
                  &quot;width&quot;: 1.0,
                  &quot;height&quot;: 1.0
              },
              &quot;warehouseLocation&quot;: {
                  &quot;latitude&quot;: 54.4,
                  &quot;longitude&quot;: -32.7
              }
          }
      ]</code></pre>
<p>You can then extract the root list to a List&lt;Map&lt;String, Object&gt;&gt; (or a any generic container of choice) using the TypeRef:</p>
<pre><code class="java">// Extract
List&lt;Map&lt;String, Object&gt;&gt; products = get(&quot;/products&quot;).as(new TypeRef&lt;List&lt;Map&lt;String, Object&gt;&gt;&gt;() {});

// Now you can do validations on the extracted objects:
assertThat(products, hasSize(2));
assertThat(products.get(0).get(&quot;id&quot;), equalTo(2));
assertThat(products.get(0).get(&quot;name&quot;), equalTo(&quot;An ice sculpture&quot;));
assertThat(products.get(0).get(&quot;price&quot;), equalTo(12.5));
assertThat(products.get(1).get(&quot;id&quot;), equalTo(3));
assertThat(products.get(1).get(&quot;name&quot;), equalTo(&quot;A blue mouse&quot;));
assertThat(products.get(1).get(&quot;price&quot;), equalTo(25.5));```</code></pre>
<h3 id="2-6-其它例子"><a href="#2-6-其它例子" class="headerlink" title="2-6.其它例子"></a>2-6.其它例子</h3><p>Micha Kops曾写过一篇很优秀的博客，里面包含大量示例（包括可检出的代码）。您可以<a href="http://www.hascode.com/2011/10/testing-restful-web-services-made-easy-using-the-rest-assured-framework/" target="_blank" rel="noopener">由此进入试读</a>。</p>
<p><a href="https://www.linkedin.com/in/basdijkstra" target="_blank" rel="noopener">Bas Dijkstra</a>也开展过不少关于rest-assured的开源研究和资源。你可以<a href="http://www.ontestautomation.com/open-sourcing-my-workshop-an-experiment/" target="_blank" rel="noopener">由此进入试读</a>，如果您想试用或者作出贡献，<a href="https://github.com/basdijkstra/workshops/" target="_blank" rel="noopener">他的github仓库</a>里有些可以尝试的练习题。</p>
<h2 id="3-关于float和double"><a href="#3-关于float和double" class="headerlink" title="3.关于float和double"></a>3.关于float和double</h2><p>浮点型数字必须和Java的基本类型”float”区分开。举个例子，如果我们看下面的JSON对象：</p>
<pre><code class="json">{

    &quot;price&quot;:12.12 

}</code></pre>
<p>如下的测试将会失败，因为我们在拿一个”double”在比较，而不是”float”：</p>
<pre><code class="java">get(&quot;/price&quot;).then().assertThat().body(&quot;price&quot;, equalTo(12.12));</code></pre>
<p>想用”float”比较的话写法应该是：</p>
<pre><code class="java">get(&quot;/price&quot;).then().assertThat().body(&quot;price&quot;, equalTo(12.12f));</code></pre>
<h2 id="4-语法关注点"><a href="#4-语法关注点" class="headerlink" title="4.语法关注点"></a>4.语法关注点</h2><p>当阅读rest-assured的博客时，你也许会看到许多使用”given / expect / when”语法的例子，举个例子：</p>
<pre><code class="java">given().
        param(&quot;x&quot;, &quot;y&quot;).
expect().
        body(&quot;lotto.lottoId&quot;, equalTo(5)).
when().
        get(&quot;/lotto&quot;);</code></pre>
<p>这是一种“遗留语法”，这实际上是rest-assured 1.x.版本用来写测试用例的方式。然而这种运作方式令许多用户迷惑甚至恼怒。这是因为一开始没有把”given / when / then”作为主要的技术来使用。所以rest-assured得2.0版本之前差不多不支持这种类似BDD-like测试的标准用法。”given / expect / when”在2.0仍然可用但是”given / when / then”可读性更强所以在测试用例中更为推荐。然而使用”given / expect / when”还有一个好处，就是所有的期望中的错误可以在同时展示出来，这是新语法做不到的（自从预期结果放在了最后面）。这意味着如果你有多个预期结果想要检验你可以：</p>
<pre><code class="java">given().
        param(&quot;x&quot;, &quot;y&quot;).
expect().
        statusCode(400).
        body(&quot;lotto.lottoId&quot;, equalTo(6)).
when().
        get(&quot;/lotto&quot;);</code></pre>
<p>rest-assured将同时报告状态码预期和响应体预期结果都是错的。将这些用新语法重写：</p>
<pre><code class="java">given().
        param(&quot;x&quot;, &quot;y&quot;).
when().
        get(&quot;/lotto&quot;).
then().
        statusCode(400).
        body(&quot;lotto.lottoId&quot;, equalTo(6));</code></pre>
<p>将会仅仅报告首个预期/断言失败的内容（比如预期状态码是400实际是200），第二个断言将不执行。您将不得不重新运行这个用例以期获取到第二个断言的结果。</p>
<p><strong>语法糖</strong></p>
<p>rest-assured中另一件值得注意的是，有些语法仅仅存在于语法糖中，举个例子，”and”在一行代码中使用可以增强可读性。</p>
<pre><code class="java">given().param(&quot;x&quot;, &quot;y&quot;).and().header(&quot;z&quot;, &quot;w&quot;).when().get(&quot;/something&quot;).then().assertThat().statusCode(200).and().body(&quot;x.y&quot;, equalTo(&quot;z&quot;));</code></pre>
<p>这等价于:</p>
<pre><code class="java">given().
        param(&quot;x&quot;, &quot;y&quot;).
        header(&quot;z&quot;, &quot;w&quot;).
when().
        get(&quot;/something&quot;).
then().
        statusCode(200).
        body(&quot;x.y&quot;, equalTo(&quot;z&quot;));</code></pre>
<h2 id="5-获得响应体信息"><a href="#5-获得响应体信息" class="headerlink" title="5.获得响应体信息"></a>5.获得响应体信息</h2><p>你也可以获得响应的内容。比方说你想通过发起一个get请求”/lotto”并获取其响应内容。你可以以多种方式：</p>
<pre><code class="java">InputStream stream = get(&quot;/lotto&quot;).asInputStream(); // Don&#39;t forget to close this one when you&#39;re done
byte[] byteArray = get(&quot;/lotto&quot;).asByteArray();
String json = get(&quot;/lotto&quot;).asString();</code></pre>
<h3 id="5-1-从已验证的响应体中提取值"><a href="#5-1-从已验证的响应体中提取值" class="headerlink" title="5-1.从已验证的响应体中提取值"></a>5-1.从已验证的响应体中提取值</h3><p>您可以从响应信息中提取值，或者使用<code>extract</code>方法仅仅返回response本身的一个实例。如何你想获取响应里的值，并将其作为接下来的请求内容，这会很有用。下面是一个叫做<code>title</code>的资源返回的JSON数据：</p>
<pre><code class="json"> {
     &quot;title&quot; : &quot;My Title&quot;,
      &quot;_links&quot;: {
              &quot;self&quot;: { &quot;href&quot;: &quot;/title&quot; },
              &quot;next&quot;: { &quot;href&quot;: &quot;/title?page=2&quot; }
           }
 }</code></pre>
<p>想验证内容类型是JSON格式且标题是<code>My Title</code>，但是还想要从中提取next的值并用来发起请求，下面是使用方法：</p>
<pre><code class="java">String nextTitleLink =
given().
        param(&quot;param_name&quot;, &quot;param_value&quot;).
when().
        get(&quot;/title&quot;).
then().
        contentType(JSON).
        body(&quot;title&quot;, equalTo(&quot;My Title&quot;)).
extract().
        path(&quot;_links.next.href&quot;);

get(nextTitleLink). ..</code></pre>
<p>如果您想提取多个值，也可以考虑返回整个响应体：</p>
<pre><code class="java">Response response = 
given().
        param(&quot;param_name&quot;, &quot;param_value&quot;).
when().
        get(&quot;/title&quot;).
then().
        contentType(JSON).
        body(&quot;title&quot;, equalTo(&quot;My Title&quot;)).
extract().
        response(); 

String nextTitleLink = response.path(&quot;_links.next.href&quot;);
String headerValue = response.header(&quot;headerName&quot;);</code></pre>
<h3 id="5-2-JSON-JsonPath"><a href="#5-2-JSON-JsonPath" class="headerlink" title="5-2.JSON(JsonPath)"></a>5-2.JSON(JsonPath)</h3><p>一旦我们取得了响应体，可以使用<a href="http://static.javadoc.io/io.restassured/json-path/3.0.1/io/restassured/path/json/JsonPath.html" target="_blank" rel="noopener">JsonPath</a>来提取相应的数据：</p>
<pre><code class="java">int lottoId = from(json).getInt(&quot;lotto.lottoId&quot;);
List&lt;Integer&gt; winnerIds = from(json).get(&quot;lotto.winners.winnerId&quot;);</code></pre>
<p>或者更高效一些:</p>
<pre><code class="java">JsonPath jsonPath = new JsonPath(json).setRoot(&quot;lotto&quot;);
int lottoId = jsonPath.getInt(&quot;lottoId&quot;);
List&lt;Integer&gt; winnerIds = jsonPath.get(&quot;winners.winnderId&quot;);</code></pre>
<p>注意这里我们独立地使用了<code>JsonPath</code>，而没有依赖rest-assured本身的功能，看<a href="https://github.com/rest-assured/rest-assured/wiki/GettingStarted" target="_blank" rel="noopener">getting started guide</a> 获取更多信息。</p>
<p><strong>JsonPath 配置</strong><br>您可以为JsonPath配置反序列化对象（object de-serializers），举个例子：</p>
<pre><code class="java">JsonPath jsonPath = new JsonPath(SOME_JSON).using(new JsonPathConfig(&quot;UTF-8&quot;));</code></pre>
<p>也可以静态配置好JsonPath，这样所有的JsonPath实例都会共享这个配置：</p>
<pre><code class="java">JsonPath.config = new JsonPathConfig(&quot;UTF-8&quot;);</code></pre>
<p>更多JsonPath的内容参照<a href="http://www.jayway.com/2013/04/12/whats-new-in-rest-assured-1-8/" target="_blank" rel="noopener">这篇博客</a>。</p>
<p>注意这里的JsonPath基于<a href='http://groovy-lang.org/processing-xml.html#_gpath' target="_blank" rel="noopener">Groovy的GPath</a>，不要和<a href='https://github.com/jayway/JsonPath' target="_blank" rel="noopener">Jayway</a>的搞混了。</p>
<h3 id="5-3-XML-XmlPath"><a href="#5-3-XML-XmlPath" class="headerlink" title="5-3.XML(XmlPath)"></a>5-3.XML(XmlPath)</h3><p>您也可以使用<a href="http://static.javadoc.io/io.restassured/xml-path/3.0.1/io/restassured/path/xml/XmlPath.html" target="_blank" rel="noopener">XmlPath</a>相应的功能：</p>
<pre><code class="java">String xml = post(&quot;/greetXML?firstName=John&amp;lastName=Doe&quot;).andReturn().asString();
// Now use XmlPath to get the first and last name
String firstName = from(xml).get(&quot;greeting.firstName&quot;);
String lastName = from(xml).get(&quot;greeting.firstName&quot;);

// or a bit more efficiently:
XmlPath xmlPath = new XmlPath(xml).setRoot(&quot;greeting&quot;);
String firstName = xmlPath.get(&quot;firstName&quot;);
String lastName = xmlPath.get(&quot;lastName&quot;);</code></pre>
<p>注意，您可以独立于rest-assured，单独使用<code>XmlPath</code>的功能，更多信息参见<a href="https://github.com/rest-assured/rest-assured/wiki/GettingStarted" target="_blank" rel="noopener">getting started guide</a>。</p>
<p><strong>XmlPath配置</strong></p>
<p>你可以配置XmlPath的对象反序列化器和字符编码，举个例子：</p>
<pre><code class="java">XmlPath xmlPath = new XmlPath(SOME_XML).using(new XmlPathConfig(&quot;UTF-8&quot;));</code></pre>
<p>也可以静态地配置XmlPath，使得所有的实例都能共享这套配置：</p>
<pre><code class="java">XmlPath.config = new XmlPathConfig(&quot;UTF-8&quot;);</code></pre>
<p>更多关于XmlPath的信息参阅<a href="http://www.jayway.com/2013/04/12/whats-new-in-rest-assured-1-8/" target="_blank" rel="noopener">这篇博客</a>。</p>
<h3 id="5-4-获取某个路径下的值"><a href="#5-4-获取某个路径下的值" class="headerlink" title="5-4.获取某个路径下的值"></a>5-4.获取某个路径下的值</h3><p>如您你只是想发起一个请求并返回一个路径下的值，你可以使用一个捷径：</p>
<pre><code class="java">int lottoId = get(&quot;/lotto&quot;).path(&quot;lotto.lottoid&quot;);</code></pre>
<p>rest-assured会基于响应体的content-type自动决定是使用JsonPath还是XmlPath。如果这个类型在rest-assured没有被定义，它将会自动到<a href="#default-parser">default parser</a>中查找。你可以自行（代码指定）决定使用哪种，比如：</p>
<pre><code class="java">String firstName = post(&quot;/greetXML?firstName=John&amp;lastName=Doe&quot;).andReturn().xmlPath().getString(&quot;firstName&quot;);</code></pre>
<p><code>xmlPath</code>, <code>jsonPath</code>和<code>htmlPath</code>都是可选项。</p>
<h3 id="5-5-Headers-cookies-status"><a href="#5-5-Headers-cookies-status" class="headerlink" title="5-5.Headers, cookies, status"></a>5-5.Headers, cookies, status</h3><p>您也可以获取 header, cookie, 状态行，状态码:</p>
<pre><code class="java">Response response = get(&quot;/lotto&quot;);

// 获取所有 headers 信息
Headers allHeaders = response.getHeaders();

// 获取单个 header 信息
String headerName = response.getHeader(&quot;headerName&quot;);

// 获取所有 cookie 键值对
Map&lt;String, String&gt; allCookies = response.getCookies();

// 获取单个 cookie 信息
String cookieValue = response.getCookie(&quot;cookieName&quot;);

// 获取状态行信息
String statusLine = response.getStatusLine();

// 获取状态码信息
int statusCode = response.getStatusCode();</code></pre>
<p>header 和 cookie 可以包含同名的多个值。</p>
<p><strong>多个 header</strong></p>
<p>要获取header的所有值，您需要首先从<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/Response.html" target="_blank" rel="noopener">Response</a>对象中获取<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/http/Headers.html" target="_blank" rel="noopener">Headers</a> 对象。您需要首先从Response对象中获取Headers对象。您可以使用Headers.getValues（<br>）方法返回一个具有所有header值的List列表。</p>
<p><strong>多个cookie</strong></p>
<p>要获取cookie的所有值，您需要首先从<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/Response.html" target="_blank" rel="noopener">Response</a>对象中获取<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/http/Cookies.html" target="_blank" rel="noopener">Cookie</a>对象。您可以使用Cookie.getValues（）方法获取所有值，该方法返回包含所有Cookie值的List列表。</p>
<p><strong>详细的Cookies信息</strong> </p>
<p>如果您需要获取Cookie的路径或过期日期等详细信息，您需要从REST Assured获取一个<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/http/Cookie.html" target="_blank" rel="noopener">detailed cookie</a>。您可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/ResponseOptions.html#getDetailedCookie-java.lang.String-" target="_blank" rel="noopener">Response.getDetailedCookie(java.lang.String)</a> 方法获取单个Cookie，包括与给定名称相关联的所有属性。</p>
<p>您还可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/ResponseOptions.html#getDetailedCookies--" target="_blank" rel="noopener">Response.getDetailedCookies()</a>方法获取所有详细的响应<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/http/Cookies.html" target="_blank" rel="noopener">cookies</a>。</p>
<h2 id="6-指定请求数据"><a href="#6-指定请求数据" class="headerlink" title="6.指定请求数据"></a>6.指定请求数据</h2><p>除了指定请求参数，您还可以指定header，Cookie，正文和Content Type。</p>
<h3 id="6-1-请求HTTP资源"><a href="#6-1-请求HTTP资源" class="headerlink" title="6-1.请求HTTP资源"></a>6-1.请求HTTP资源</h3><p>您通常通过调用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/specification/RequestSpecification.html" target="_blank" rel="noopener">request specification</a>中的“HTTP方法”执行请求。例如：</p>
<pre><code class="java">when().get(&quot;/x&quot;). ..;</code></pre>
<p>其中<code>get</code>是HTTP请求方法。</p>
<p>从REST Assured 3.0.0开始，您可以通过使用该方法为请求使用任何HTTP动词。</p>
<pre><code class="java">when().
       request(&quot;CONNECT&quot;, &quot;/somewhere&quot;).
then().
       statusCode(200);</code></pre>
<p>这将向服务器发送“连接”请求。</p>
<h3 id="6-2-参数化"><a href="#6-2-参数化" class="headerlink" title="6-2.参数化"></a>6-2.参数化</h3><p>通常您可以这样指定参数：</p>
<pre><code class="java">given().
       param(&quot;param1&quot;, &quot;value1&quot;).
       param(&quot;param2&quot;, &quot;value2&quot;).
when().
       get(&quot;/something&quot;);</code></pre>
<p>REST Assured将自动尝试基于HTTP方法确定哪个参数类型（即查询或表单参数）。在GET的情况下，查询参数将被自动使用，在POST的情况下将使用表单参数。在某些情况下，重要的是在PUT或POST中分离表单和查询参数。你可以这样使用：</p>
<pre><code class="java">given().
       formParam(&quot;formParamName&quot;, &quot;value1&quot;).
       queryParam(&quot;queryParamName&quot;, &quot;value2&quot;).
when().
       post(&quot;/something&quot;);</code></pre>
<p>参数也可以url上进行设置：</p>
<pre><code class="java">..when().get(&quot;/name?firstName=John&amp;lastName=Doe&quot;);</code></pre>
<p>参数如果上传的是文件，字节数组，输入流或文本的可以参照<a href="#Multi-part表单数据">Multi-part类型的表单数据</a>部分</p>
<h3 id="6-3-多值参数"><a href="#6-3-多值参数" class="headerlink" title="6-3.多值参数"></a>6-3.多值参数</h3><p>多值参数是每个参数名称具有多于一个值的参数（即，每个名称的值的列表）。您可以使用var-args指定这些值：</p>
<pre><code class="java">given().param(&quot;myList&quot;, &quot;value1&quot;, &quot;value2&quot;). .. </code></pre>
<p>或者使用 list 列表：</p>
<pre><code class="java">List&lt;String&gt; values = new ArrayList&lt;String&gt;();
values.add(&quot;value1&quot;);
values.add(&quot;value2&quot;);

given().param(&quot;myList&quot;, values). .. </code></pre>
<h3 id="6-4-无值参数"><a href="#6-4-无值参数" class="headerlink" title="6-4.无值参数"></a>6-4.无值参数</h3><p>您还可以指定一个没有值的请求或表单参数：</p>
<pre><code class="java">given().param(&quot;paramName&quot;). ..</code></pre>
<h3 id="6-5-路径参数"><a href="#6-5-路径参数" class="headerlink" title="6-5.路径参数"></a>6-5.路径参数</h3><p>您还可以在请求中指定所谓的路径参数，例如</p>
<pre><code class="java">post(&quot;/reserve/{hotelId}/{roomNumber}&quot;, &quot;My Hotel&quot;, 23);</code></pre>
<p>这些种类的路径参数在REST Assured中称为“未命名路径参数”，因为它们是基于索引的（<code>hotelId</code>将等于“My Hotel”，因为它是第一个占位符）。</p>
<p>您还可以使用命名路径参数：</p>
<pre><code class="java">given().
        pathParam(&quot;hotelId&quot;, &quot;My Hotel&quot;).
        pathParam(&quot;roomNumber&quot;, 23).
when(). 
        post(&quot;/reserve/{hotelId}/{roomNumber}&quot;).
then().
         ..</code></pre>
<p>路径参数使得更容易读取请求路径，且使请求路径能够在具有不同参数值的许多测试中容易地重复使用。</p>
<p>从版本2.8.0开始，您可以混合未赋值和赋值好的路径参数：</p>
<pre><code class="java">given().
        pathParam(&quot;hotelId&quot;, &quot;My Hotel&quot;).        
when(). 
        post(&quot;/reserve/{hotelId}/{roomNumber}&quot;, 23).
then().
         ..</code></pre>
<p>这里 <code>roomNumber</code> 的值<code>My Hotel</code>将被替换为 <code>23</code>.</p>
<p>注意，指定太少或太多的参数将导致错误消息。对于高级用例，您可以从[过滤器]（＃过滤器）添加，更改，删除（甚至冗余的路径参数）。</p>
<h3 id="6-6-Cookie"><a href="#6-6-Cookie" class="headerlink" title="6-6.Cookie"></a>6-6.Cookie</h3><p>通常模式下，您可以通过以下方法指定Cookie：</p>
<pre><code class="java">given().cookie(&quot;username&quot;, &quot;John&quot;).when().get(&quot;/cookie&quot;).then().body(equalTo(&quot;username&quot;));</code></pre>
<p>也可以像这样给cookie指定多个值：</p>
<pre><code class="java">given().cookie(&quot;cookieName&quot;, &quot;value1&quot;, &quot;value2&quot;). ..</code></pre>
<p>这将创建两个cookie：cookieName = value1和cookieName = value2。</p>
<p>您还可以使用以下方式指定详细的Cookie：</p>
<pre><code class="java">Cookie someCookie = new Cookie.Builder(&quot;some_cookie&quot;, &quot;some_value&quot;).setSecured(true).setComment(&quot;some comment&quot;).build();
given().cookie(someCookie).when().get(&quot;/cookie&quot;).then().assertThat().body(equalTo(&quot;x&quot;));</code></pre>
<p>或同时指定cookies：</p>
<pre><code class="java">Cookie cookie1 = Cookie.Builder(&quot;username&quot;, &quot;John&quot;).setComment(&quot;comment 1&quot;).build();
Cookie cookie2 = Cookie.Builder(&quot;token&quot;, 1234).setComment(&quot;comment 2&quot;).build();
Cookies cookies = new Cookies(cookie1, cookie2);
given().cookies(cookies).when().get(&quot;/cookie&quot;).then().body(equalTo(&quot;username, token&quot;));</code></pre>
<h3 id="6-7-Header"><a href="#6-7-Header" class="headerlink" title="6-7.Header"></a>6-7.Header</h3><pre><code class="java">given().header(&quot;MyHeader&quot;, &quot;Something&quot;).and(). ..
given().headers(&quot;MyHeader&quot;, &quot;Something&quot;, &quot;MyOtherHeader&quot;, &quot;SomethingElse&quot;).and(). ..</code></pre>
<p>也可以给一个headers指定多个值：</p>
<pre><code class="java">given().header(&quot;headerName&quot;, &quot;value1&quot;, &quot;value2&quot;). ..</code></pre>
<p>这将创建两个header,headerName = value1和headerName = value2</p>
<p><strong>Header 合并/覆盖</strong></p>
<p>默认情况下，header合并可以这样：</p>
<pre><code class="java">given().header(&quot;x&quot;, &quot;1&quot;).header(&quot;x&quot;, &quot;2&quot;). ..</code></pre>
<p>请求将包含两个标头，“x：1”和“x：2”。您可以在[HeaderConfig]（<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/HeaderConfig.html）的基础上进行更改。例如：" target="_blank" rel="noopener">http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/HeaderConfig.html）的基础上进行更改。例如：</a></p>
<pre><code class="java">given().
        config(RestAssuredConfig.config().headerConfig(headerConfig().overwriteHeadersWithName(&quot;x&quot;))).
        header(&quot;x&quot;, &quot;1&quot;).
        header(&quot;x&quot;, &quot;2&quot;).
when().
        get(&quot;/something&quot;).
...</code></pre>
<p>这意味着只有header “x = 2”被发送到服务器</p>
<h3 id="6-8-Content-Type"><a href="#6-8-Content-Type" class="headerlink" title="6-8.Content Type"></a>6-8.Content Type</h3><pre><code class="java">given().contentType(ContentType.TEXT). ..
given().contentType(&quot;application/json&quot;). ..</code></pre>
<h3 id="6-9-请求正文"><a href="#6-9-请求正文" class="headerlink" title="6-9.请求正文"></a>6-9.请求正文</h3><pre><code class="java">given().body(&quot;some body&quot;). .. // Works for POST, PUT and DELETE requests
given().request().body(&quot;some body&quot;). .. // More explicit (optional)</code></pre>
<pre><code class="java">given().body(new byte[]{42}). .. // Works for POST, PUT and DELETE
given().request().body(new byte[]{42}). .. // More explicit (optional)</code></pre>
<p>您还可以将Java对象序列化为JSON或XML。点击<a href="#序列化">这里</a>了解详情。</p>
<h2 id="7-验证响应数据"><a href="#7-验证响应数据" class="headerlink" title="7.验证响应数据"></a>7.验证响应数据</h2><p>您还可以验证状态码，状态行，Cookie，headers，内容类型和正文。</p>
<h3 id="7-1-响应体"><a href="#7-1-响应体" class="headerlink" title="7-1.响应体"></a>7-1.响应体</h3><p>请参阅使用示例，例如<a href="#例一-JSON">JSON</a> 或 <a href="#例2-XML">XML</a>.</p>
<p>您还可以将响应正文映射到Java对象，单击<a href="#deserialization">这里</a> 了解详细信息。</p>
<h3 id="7-2-Cookie"><a href="#7-2-Cookie" class="headerlink" title="7-2.Cookie"></a>7-2.Cookie</h3><pre><code class="java">get(&quot;/x&quot;).then().assertThat().cookie(&quot;cookieName&quot;, &quot;cookieValue&quot;). ..
get(&quot;/x&quot;).then().assertThat().cookies(&quot;cookieName1&quot;, &quot;cookieValue1&quot;, &quot;cookieName2&quot;, &quot;cookieValue2&quot;). ..
get(&quot;/x&quot;).then().assertThat().cookies(&quot;cookieName1&quot;, &quot;cookieValue1&quot;, &quot;cookieName2&quot;, containsString(&quot;Value2&quot;)). ..</code></pre>
<h3 id="7-3-状态码"><a href="#7-3-状态码" class="headerlink" title="7-3.状态码"></a>7-3.状态码</h3><pre><code class="java">get(&quot;/x&quot;).then().assertThat().statusCode(200). ..
get(&quot;/x&quot;).then().assertThat().statusLine(&quot;something&quot;). ..
get(&quot;/x&quot;).then().assertThat().statusLine(containsString(&quot;some&quot;)). ..</code></pre>
<h3 id="7-4-Header"><a href="#7-4-Header" class="headerlink" title="7-4.Header"></a>7-4.Header</h3><pre><code class="java">get(&quot;/x&quot;).then().assertThat().header(&quot;headerName&quot;, &quot;headerValue&quot;). ..
get(&quot;/x&quot;).then().assertThat().headers(&quot;headerName1&quot;, &quot;headerValue1&quot;, &quot;headerName2&quot;, &quot;headerValue2&quot;). ..
get(&quot;/x&quot;).then().assertThat().headers(&quot;headerName1&quot;, &quot;headerValue1&quot;, &quot;headerName2&quot;, containsString(&quot;Value2&quot;)). ..</code></pre>
<p>还可以在验证头时使用映射函数。 例如，假设您要验证“Content-Length”头部小于1000.然后，您可以使用映射函数首先将头值转换为int，然后在使用Hamcrest验证前使用“整数” 匹配器：</p>
<pre><code class="java">get(&quot;/something&quot;).then().assertThat().header(&quot;Content-Length&quot;, Integer::parseInt, lessThan(1000));</code></pre>
<h3 id="7-5-Content-Type"><a href="#7-5-Content-Type" class="headerlink" title="7-5.Content-Type"></a>7-5.Content-Type</h3><pre><code class="java">get(&quot;/x&quot;).then().assertThat().contentType(ContentType.JSON). ..</code></pre>
<h3 id="7-6-内容全匹配"><a href="#7-6-内容全匹配" class="headerlink" title="7-6.内容全匹配"></a>7-6.内容全匹配</h3><pre><code class="java">get(&quot;/x&quot;).then().assertThat().body(equalTo(&quot;something&quot;)). ..</code></pre>
<h3 id="7-7-关联类型验证"><a href="#7-7-关联类型验证" class="headerlink" title="7-7.关联类型验证"></a>7-7.关联类型验证</h3><p>您可以使用响应中的数据来验证响应的另一部分。 例如，从服务端返回的以下JSON：</p>
<pre><code class="json">{ &quot;userId&quot; : &quot;some-id&quot;, &quot;href&quot; : &quot;http://localhost:8080/some-id&quot; }</code></pre>
<p>您可能会注意到，“href”属性以“userId”属性的值结尾。 如果我们想验证这个，我们可以实现一个io.restassured.matcher.ResponseAwareMatcher，可以：</p>
<pre><code class="java">get(&quot;/x&quot;).then().body(&quot;href&quot;, new ResponseAwareMatcher&lt;Response&gt;() {
                                  public Matcher&lt;?&gt; matcher(Response response) {
                                          return equalTo(&quot;http://localhost:8080/&quot; + response.path(&quot;userId&quot;));
                                  }
                       });</code></pre>
<p>如果您使用Java 8，你可以使用lambda表达式：</p>
<pre><code class="java">get(&quot;/x&quot;).then().body(&quot;href&quot;, response -&gt; equalTo(&quot;http://localhost:8080/&quot; + response.path(&quot;userId&quot;));</code></pre>
<p>有一些预定义的匹配器，您可以使用在io.restassured.matcher.RestAssuredMatchers（或io.restassured.module.mockmvc.matcher.RestAssuredMockMvcMatchers如果使用spring-mock-mvc模块）中定义。 例如：</p>
<pre><code class="java">get(&quot;/x&quot;).then().body(&quot;href&quot;, endsWithPath(&quot;userId&quot;));</code></pre>
<p>ResponseAwareMatchers也可以与另一个ResponseAwareMatcher或与Hamcrest Matcher组成。 例如：</p>
<pre><code class="java">get(&quot;/x&quot;).then().body(&quot;href&quot;, and(startsWith(&quot;http:/localhost:8080/&quot;), endsWithPath(&quot;userId&quot;)));</code></pre>
<p> <code>and</code> 方法是由<code>io.restassured.matcher.ResponseAwareMatcherComposer</code>静态导入的。</p>
<h3 id="7-8-计算响应时间"><a href="#7-8-计算响应时间" class="headerlink" title="7-8.计算响应时间"></a>7-8.计算响应时间</h3><p>从 REST Assured  2.8.0开始支持测量响应时间，例如：</p>
<pre><code class="java">long timeInMs = get(&quot;/lotto&quot;).time()</code></pre>
<p>或使用特定时间单位：</p>
<pre><code class="java">long timeInSeconds = get(&quot;/lotto&quot;).timeIn(SECONDS);
</code></pre>
<p>其中SECONDS只是一个标准的TimeUnit。 您还可以使用DSL验证：</p>
<pre><code class="java">when().
      get(&quot;/lotto&quot;).
then().
      time(lessThan(2000L)); // Milliseconds</code></pre>
<p>或</p>
<pre><code class="java">when().
      get(&quot;/lotto&quot;).
then().
      time(lessThan(2L), SECONDS);</code></pre>
<p>需要注意的是，您只能参考性地将这些测量数据与服务器请求处理时间相关联（因为响应时间将包括HTTP往返和REST Assured处理时间等，不能做到十分准确）。</p>
<h2 id="8-认证"><a href="#8-认证" class="headerlink" title="8.认证"></a>8.认证</h2><p>REST assured还支持多种认证方案，例如OAuth，摘要，证书，表单和抢占式基本认证。 您可以为每个请求设置身份验证：</p>
<pre><code class="java">given().auth().basic(&quot;username&quot;, &quot;password&quot;). ..</code></pre>
<p>也可以为所有请求定义身份验证：</p>
<pre><code class="java">RestAssured.authentication = basic(&quot;username&quot;, &quot;password&quot;);</code></pre>
<p>或者您也可以使用 <a href="#模式复用">specification</a>.</p>
<h3 id="8-1-基本认证"><a href="#8-1-基本认证" class="headerlink" title="8-1.基本认证"></a>8-1.基本认证</h3><p>有两种类型的基本认证，抢占和“受质询的基本认证”。</p>
<h4 id="8-1-1-抢占式"><a href="#8-1-1-抢占式" class="headerlink" title="8-1-1.抢占式"></a>8-1-1.抢占式</h4><p>服务器在某些情况下给出未授权响应之前发送基本认证凭证，从而减少进行附加连接的开销。 大多数情况下可以这么使用：</p>
<pre><code class="java">given().auth().preemptive().basic(&quot;username&quot;, &quot;password&quot;).when().get(&quot;/secured/hello&quot;).then().statusCode(200);</code></pre>
<h4 id="8-1-2-受质询的基本认证"><a href="#8-1-2-受质询的基本认证" class="headerlink" title="8-1-2.受质询的基本认证"></a>8-1-2.受质询的基本认证</h4><p>使用“受质询的基本认证”时，REST Assured将不提供凭据，除非服务器已明确要求。 这意味着REST Assured将向服务器发出一个附加请求，以便进行质询，然后再次处理相同的请求，但此时会在header中设置基本凭据。</p>
<pre><code class="java">given().auth().basic(&quot;username&quot;, &quot;password&quot;).when().get(&quot;/secured/hello&quot;).then().statusCode(200);</code></pre>
<h3 id="8-2-摘要认证"><a href="#8-2-摘要认证" class="headerlink" title="8-2.摘要认证"></a>8-2.摘要认证</h3><p>目前只支持受质询的摘要认证：</p>
<pre><code class="java">given().auth().digest(&quot;username&quot;, &quot;password&quot;).when().get(&quot;/secured&quot;). ..</code></pre>
<h3 id="8-3-表单认证"><a href="#8-3-表单认证" class="headerlink" title="8-3.表单认证"></a>8-3.表单认证</h3><p><a href="https://en.wikipedia.org/wiki/Form-based_authentication" target="_blank" rel="noopener">表单认证</a>在互联网上非常流行。 它通常与用户在网页上填写其凭据（用户名和密码），然后在按某种类型的登录按钮时发起请求。 提供表单身份验证基础的一个非常简单的HTML页面可能如下所示</p>
<pre><code class="html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Login&lt;/title&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;form action=&quot;j_spring_security_check&quot; method=&quot;POST&quot;&gt;
      &lt;table&gt;
        &lt;tr&gt;&lt;td&gt;User:&amp;nbsp;&lt;/td&gt;&lt;td&gt;&lt;input type=&#39;text&#39; name=&#39;j_username&#39;&gt;&lt;/td&gt;&lt;/tr&gt;
        &lt;tr&gt;&lt;td&gt;Password:&lt;/td&gt;&lt;td&gt;&lt;input type=&#39;password&#39; name=&#39;j_password&#39;&gt;&lt;/td&gt;&lt;/tr&gt;
          &lt;tr&gt;&lt;td colspan=&#39;2&#39;&gt;&lt;input name=&quot;submit&quot; type=&quot;submit&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
       &lt;/table&gt;
        &lt;/form&gt;
      &lt;/body&gt;
 &lt;/html&gt;</code></pre>
<p>也就是说 服务器期望用户填写“j_username”和“j_password”输入字段，然后按“提交”登录。 使用REST Assured，您可以测试受表单身份验证保护的服务，如下所示：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<p> 在REST中使用此类表单身份验证时，会导致为检索包含登录详细信息的网页而向服务器发出附加请求。 REST Assured将尝试解析此页面并查找两个输入字段（用户名和密码）以及表单操作的URI。 这可能失败，取决于网页的复杂性。 更好的选择是在设置表单身份验证时提供这些详细信息。 在这种情况下，可以：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;, new FormAuthConfig(&quot;/j_spring_security_check&quot;, &quot;j_username&quot;, &quot;j_password&quot;)).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<p>这样REST Assured不需要提出额外的请求并解析网页。 还有一个预定义的FormAuthConfig称为<code>springSecurity</code>，如果你使用默认的Spring Security属性，可以使用它：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;, FormAuthConfig.springSecurity()).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<h4 id="8-3-1-CSRF"><a href="#8-3-1-CSRF" class="headerlink" title="8-3-1.CSRF"></a>8-3-1.CSRF</h4><p>如今，服务器要求请求中提供一个<a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery" target="_blank" rel="noopener">CSRF</a> token是常有的事了，这可以抵御多种类型的攻击。rest-assured支持解析并自动给服务器供应一个CSRF token。为此，rest-assured必须先发起一个追加请求来解析该网站（的部分内容）。</p>
<p>你可以通过下面的代码启用对CSRF的支持：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;, formAuthConfig().withAutoDetectionOfCsrf()).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<p>现在rest-assured将会自动尝试侦测这个网站是否包含CSRF token机制。为了使rest-assured的暴力破解更加顺利，可能会提供一个CSRF域的名称（这里我们假设我们正在使用Spring的安全默认值，因此我们可以使用预定义的<code>springSecurity</code>表单认证配置）：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;, springSecurity().withCsrfFieldName(&quot;_csrf&quot;)).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<p>我们至此已经告诉rest-assured去查找名为”_csrf”的CSRF域了（然而这虽然会比自动侦测更快，也更容易出错）。</p>
<p>默认情况下CSRF值将会作为一个请求参数，但是如果必要你也可以配置其放在请求的header中：</p>
<pre><code class="java">given().
        auth().form(&quot;John&quot;, &quot;Doe&quot;, springSecurity().withCsrfFieldName(&quot;_csrf&quot;).sendCsrfTokenAsHeader()).
when().
        get(&quot;/formAuth&quot;);
then().
        statusCode(200);</code></pre>
<h4 id="8-3-2-附加字段"><a href="#8-3-2-附加字段" class="headerlink" title="8-3-2.附加字段"></a>8-3-2.附加字段</h4><p>Since version 3.1.0 REST Assured can include additional input fields when using form authentication. Just use the FormAuthConfig and specify the additional values to include. For example if you have an html page that looks like this:</p>
<pre><code class="html">html&gt;
&lt;head&gt;
   &lt;title&gt;Login&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form action=&quot;/login&quot; method=&quot;POST&quot;&gt;
   &lt;table&gt;
       &lt;tr&gt;
           &lt;td&gt;User:&amp;nbsp;&lt;/td&gt;
           &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;j_username&quot;&gt;&lt;/td&gt;
       &lt;/tr&gt;
       &lt;tr&gt;
           &lt;td&gt;Password:&lt;/td&gt;
           &lt;td&gt;&lt;input type=&quot;password&quot; name=&quot;j_password&quot;&gt;&lt;/td&gt;
       &lt;/tr&gt;
       &lt;tr&gt;
           &lt;td colspan=&quot;2&quot;&gt;&lt;input name=&quot;submit&quot; type=&quot;submit&quot;/&gt;&lt;/td&gt;
       &lt;/tr&gt;
   &lt;/table&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;firstInputField&quot; value=&quot;value1&quot;/&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;secondInputField&quot; value=&quot;value2&quot;/&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>and you’d like to include the value of form parameters firstInputField and secondInputField you can do like this:</p>
<pre><code class="java">given().auth().form(&quot;username&quot;, &quot;password&quot;, formAuthConfig().withAdditionalFields(&quot;firstInputField&quot;, &quot;secondInputField&quot;). ..
</code></pre>
<p>REST Assured will automatically parse the HTML page, find the values for the additional fields and include them as form parameters in the login request.</p>
<h3 id="8-4-OAut"><a href="#8-4-OAut" class="headerlink" title="8-4.OAut"></a>8-4.OAut</h3><p>为了使用OAuth1和OAuth2（关于查询/请求参数签名方面的机制），您需要添加<a href="https://github.com/fernandezpablo85/scribe-java" target="_blank" rel="noopener">Scribe</a>到classpath中（如果你正在使用2.1.0或者更早之前版本的rest-assured，请参考<a href="https://github.com/rest-assured/rest-assured/wiki/Usage_Legacy#OAuth" target="_blank" rel="noopener">旧版指南</a>）。如果是maven请添加以下的依赖：</p>
<pre><code class="xml">&lt;dependency&gt;
            &lt;groupId&gt;org.scribe&lt;/groupId&gt;
            &lt;artifactId&gt;scribe&lt;/artifactId&gt;
            &lt;version&gt;1.3.7&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p>如果您没有使用maven，可以<a href="https://github.com/fernandezpablo85/scribe-java/releases" target="_blank" rel="noopener">下载</a>一个Scribe发行包并把它发在classpath下。</p>
<h4 id="8-4-1-OAuth-1"><a href="#8-4-1-OAuth-1" class="headerlink" title="8-4-1.OAuth 1"></a>8-4-1.OAuth 1</h4><p>OAuth1要求<a href="#oauth">Scribe</a>在classpath中。为使用auth1的认证您可以：</p>
<pre><code class="java">given().auth().oauth(..). ..</code></pre>
<h4 id="8-4-2-OAuth-2"><a href="#8-4-2-OAuth-2" class="headerlink" title="8-4-2.OAuth 2"></a>8-4-2.OAuth 2</h4><p>自从2.5.0版本您可以依赖于<a href="#oauth">Scribe</a>使用OAuth2的认证：</p>
<pre><code class="java">given().auth().oauth2(accessToken). ..</code></pre>
<p>这将会把OAuth2的<code>accessToken</code>放入header中。想要更加显式的操作可以：</p>
<pre><code class="java">given().auth().preemptive().oauth2(accessToken). ..</code></pre>
<p>这里之所以存在<code>given().auth().oauth2(..)</code>这种语法是为了向后兼容(做的是相同的事情)。如果你需要在请求参数中提供一个OAuth2 token，您需要把<a href="#oauth">Scribe</a>放在classpath下，接下来：</p>
<pre><code class="java">given().auth().oauth2(accessToken, OAuthSignature.QUERY_STRING). ..</code></pre>
<h3 id="8-5-自定义身份验证"><a href="#8-5-自定义身份验证" class="headerlink" title="8-5.自定义身份验证"></a>8-5.自定义身份验证</h3><p>rest-assured允许您创建一个自定义的身份验证。你可以通过实现<code>io.restassured.spi.AuthFilter</code>接口，并作为一个过滤器。假设您的安全机制，是由两个header值相加然后组成一个新的叫做”AUTH”的header（当然这并不安全）。然后您可以这样做（Java 8的语法）：</p>
<pre><code class="java">given().
        filter((requestSpec, responseSpec, ctx) -&gt; {
            String header1 = requestSpec.getHeaders().getValue(&quot;header1&quot;);
            String header2 = requestSpec.getHeaders().getValue(&quot;header2&quot;);
            requestSpec.header(&quot;AUTH&quot;, header1 + header2);
            return ctx.next(requestSpec, responseSpec);
        }).
when().
        get(&quot;/customAuth&quot;).
then().
  statusCode(200);</code></pre>
<p>使用<code>AuthFilter</code>而不是<code>Filter</code>的原因是，当我们执行<code>given().auth().none(). ..</code>类似这样的操作时<code>AuthFilters</code>会被自动移除。</p>
<h2 id="9-Multi-part表单数据"><a href="#9-Multi-part表单数据" class="headerlink" title="9.Multi-part表单数据"></a>9.Multi-part表单数据</h2><p>通常我们在向服务器传输大容量的数据时（译者注：比如文件）会使用multipart表单数据技术。rest-assured提供了一种<code>multiPart</code>方法来辨别这究竟是文件、二进制序列、输入流还是上传的文本。表单中上传一个文件可以这样：</p>
<pre><code class="java">given().
        multiPart(new File(&quot;/path/to/file&quot;)).
when().
        post(&quot;/upload&quot;);</code></pre>
<p>它将会假设有一个control叫做”file”。在HTML中这意味着input标签的属性值为file。为了解释得更清楚请看下面的HTML表单：</p>
<pre><code class="html">&lt;form id=&quot;uploadForm&quot; action=&quot;/upload&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
        &lt;input type=&quot;file&quot; name=&quot;file&quot; size=&quot;40&quot;&gt;
        &lt;input type=submit value=&quot;Upload!&quot;&gt;
&lt;/form&gt;</code></pre>
<p>在这个例子中control的名字就是一个属性名为file的input标签。如果您使用的control名不是这个，需要指定：</p>
<pre><code class="java">given().
        multiPart(&quot;controlName&quot;, new File(&quot;/path/to/file&quot;)).
when().
        post(&quot;/upload&quot;);</code></pre>
<p>在同一个请求中提供多个”multi-parts”事务也是可能的：</p>
<pre><code class="java">byte[] someData = ..
given().
        multiPart(&quot;controlName1&quot;, new File(&quot;/path/to/file&quot;)).
        multiPart(&quot;controlName2&quot;, &quot;my_file_name.txt&quot;, someData).
        multiPart(&quot;controlName3&quot;, someJavaObject, &quot;application/json&quot;).
when().
        post(&quot;/upload&quot;);</code></pre>
<p>更多高级使用方法可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/builder/MultiPartSpecBuilder.html" target="_blank" rel="noopener">MultiPartSpecBuilder</a>。举个例子：</p>
<pre><code class="java">Greeting greeting = new Greeting();
greeting.setFirstName(&quot;John&quot;);
greeting.setLastName(&quot;Doe&quot;);

given().
        multiPart(new MultiPartSpecBuilder(greeting, ObjectMapperType.JACKSON_2)
                .fileName(&quot;greeting.json&quot;)
                .controlName(&quot;text&quot;)
                .mimeType(&quot;application/vnd.custom+json&quot;).build()).
when().
        post(&quot;/multipart/json&quot;).
then().
        statusCode(200);</code></pre>
<p>你可以通过使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/MultiPartConfig.html" target="_blank" rel="noopener">MultiPartConfig</a>指定默认的control名和文件名。举个例子：</p>
<pre><code class="java">given().config(config().multiPartConfig(multiPartConfig().defaultControlName(&quot;something-else&quot;))). ..</code></pre>
<p>这就会默认把control名配置为”something-else”而不是”file”。</p>
<p>其它用法请查阅 <a href="http://blog.jayway.com/2011/09/15/multipart-form-data-file-uploading-made-simple-with-rest-assured/" target="_blank" rel="noopener">这篇博客</a>。</p>
<h2 id="10-对象映射"><a href="#10-对象映射" class="headerlink" title="10.对象映射"></a>10.对象映射</h2><p>rest-assured支持从JSON和XML中映射Java对象。映射JSON需要classpath中有Jackson或者Gson才能使用，XML则需要JAXB。</p>
<h3 id="10-1-序列化"><a href="#10-1-序列化" class="headerlink" title="10-1.序列化"></a>10-1.序列化</h3><p>假设我们有下面的Java对象：</p>
<pre><code class="java">public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}</code></pre>
<p>您需要将这个对象序列化为JSON并发送到请求中。可以有多种方式：</p>
<h4 id="10-1-1-基于Content-Type的序列化"><a href="#10-1-1-基于Content-Type的序列化" class="headerlink" title="10-1-1.基于Content-Type的序列化"></a>10-1-1.基于Content-Type的序列化</h4><pre><code class="java">Message message = new Message();
message.setMessage(&quot;My messagee&quot;);
given().
       contentType(&quot;application/json&quot;).
       body(message).
when().
      post(&quot;/message&quot;);</code></pre>
<p>在这个例子里，由于请求中的content-type被设置为”application/json”，rest-assured也就会把对象序列化为JSON。rest-assured首先会在您的classpath中寻找Jackson，如果没有则使用Gson。如果您把请求中的content-type修改为”application/xml”，rest-assured将会使用JAXB把对象序列化为XML。如果没有指定content-type，rest-assured会按照以下的优先级进行序列化：</p>
<ol>
<li>使用Jackson 2将对象序列化为JSON（Faster Jackson (databind)）</li>
<li>使用Jackson将对象序列化为JSON（databind）</li>
<li>使用Gson将对象序列化为JSON</li>
<li>使用JAXB将对象序列化为XML</li>
</ol>
<p>rest-assured也关心content-type的字符集（charset）等等。</p>
<pre><code class="java">Message message = new Message();
message.setMessage(&quot;My messagee&quot;);
given().
       contentType(&quot;application/json; charset=UTF-16&quot;).
       body(message).
when().
      post(&quot;/message&quot;);</code></pre>
<p>您也可以把<code>Message</code>这个实例序列化为一个表单参数：</p>
<pre><code class="java">Message message = new Message();
message.setMessage(&quot;My messagee&quot;);
given().
       contentType(&quot;application/json; charset=UTF-16&quot;).
       formParam(&quot;param1&quot;, message).
when().
      post(&quot;/message&quot;);</code></pre>
<p>这个message对象将会被实例化为utf-16编码的JSON（如果有Jackson或者Gson）。</p>
<h4 id="10-1-2-由HashMap创建JSON"><a href="#10-1-2-由HashMap创建JSON" class="headerlink" title="10-1-2.由HashMap创建JSON"></a>10-1-2.由HashMap创建JSON</h4><p>您也可以提供一个Map，由此rest-assured可以创建一个JSON。</p>
<pre><code class="java">Map&lt;String, Object&gt;  jsonAsMap = new HashMap&lt;&gt;();
jsonAsMap.put(&quot;firstName&quot;, &quot;John&quot;);
jsonAsMap.put(&quot;lastName&quot;, &quot;Doe&quot;);

given().
        contentType(JSON).
        body(jsonAsMap).
when().
        post(&quot;/somewhere&quot;).
then().
        statusCode(200);</code></pre>
<p>这将会产生一个JSON数据（JSON payload）：</p>
<pre><code class="json">{ &quot;firstName&quot; : &quot;John&quot;, &quot;lastName&quot; : &quot;Doe&quot; }</code></pre>
<h4 id="10-1-3-使用显式序列化器"><a href="#10-1-3-使用显式序列化器" class="headerlink" title="10-1-3.使用显式序列化器"></a>10-1-3.使用显式序列化器</h4><p>如果您的classpath中同时有多个对象、或者不考虑content-type的设置，可以显示地指定一个序列化器。</p>
<pre><code class="java">Message message = new Message();
message.setMessage(&quot;My messagee&quot;);
given().
       body(message, ObjectMapperType.JAXB).
when().
      post(&quot;/message&quot;);</code></pre>
<p>在这个例子中message对象将会被JAXB序列化为一个XML。</p>
<h3 id="10-2-反序列化"><a href="#10-2-反序列化" class="headerlink" title="10-2.反序列化"></a>10-2.反序列化</h3><p>让我们再次假设我们有以下的Java对象：</p>
<pre><code class="java">public class Message {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}</code></pre>
<p>我们需要把响应体反序列化为一个Message对象。</p>
<h4 id="10-2-1-基于Content-Type的反序列化"><a href="#10-2-1-基于Content-Type的反序列化" class="headerlink" title="10-2-1.基于Content-Type的反序列化"></a>10-2-1.基于Content-Type的反序列化</h4><p>假设服务端返回一个这样的JSON：</p>
<pre><code class="json">{&quot;message&quot;:&quot;My message&quot;}</code></pre>
<p>将它反序列化为一个Message对象：</p>
<pre><code class="java">Message message = get(&quot;/message&quot;).as(Message.class);</code></pre>
<p>为此响应体的content-type必须是”application/json”（或者其它包含“json”的类型）。如果服务端返回：</p>
<pre><code class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;message&gt;
      &lt;message&gt;My message&lt;/message&gt;
&lt;/message&gt;</code></pre>
<p>且content-type是”application/xml”，代码可以完全不用修改：</p>
<pre><code class="java">Message message = get(&quot;/message&quot;).as(Message.class);</code></pre>
<h4 id="10-2-2-自定义类型content-type反序列化"><a href="#10-2-2-自定义类型content-type反序列化" class="headerlink" title="10-2-2.自定义类型content-type反序列化"></a>10-2-2.自定义类型content-type反序列化</h4><p>如果服务端返回一个自定义的content-type，假设是”application/something”，你仍然想使用rest-assured的对象映射的话，这有两种方法。你可以使用<a href="http://code.google.com/p/rest-assured/wiki/Usage#Using_an_Explicit_Deserializer" target="_blank" rel="noopener">显式指定</a>的方法或者为自定义的content-type注册一个解析器：</p>
<pre><code class="java">Message message = expect().parser(&quot;application/something&quot;, Parser.XML).when().get(&quot;/message&quot;).as(Message.class);</code></pre>
<p>或</p>
<pre><code class="java">Message message = expect().defaultParser(Parser.XML).when().get(&quot;/message&quot;).as(Message.class);</code></pre>
<p>你也可以注册一个默认解析器，或者静态式注册一个自定义的解析器，也可以使用<a href="#模式复用">模式（specifications）</a>。</p>
<h4 id="10-2-3-使用显式反序列化器"><a href="#10-2-3-使用显式反序列化器" class="headerlink" title="10-2-3.使用显式反序列化器"></a>10-2-3.使用显式反序列化器</h4><p>如果您的classpath下同时有多个对象或者不在意响应体的content-type，你可以使用显示的反序列化器。</p>
<pre><code class="java">Message message = get(&quot;/message&quot;).as(Message.class, ObjectMapperType.GSON);</code></pre>
<h3 id="10-3-配置"><a href="#10-3-配置" class="headerlink" title="10-3.配置"></a>10-3.配置</h3><p>您可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/ObjectMapperConfig.html" target="_blank" rel="noopener">ObjectMapperConfig</a>配置预定义的对象映射，并传递给<a href="#detailed-configuration">细节配置</a>。举个例子，你可以将GSON的命名策略改为LowerCaseWithUnderscores（译者注：一种策略，将大写字母改为小写字母并添加下划线）：</p>
<pre><code class="java">RestAssured.config = RestAssuredConfig.config().objectMapperConfig(objectMapperConfig().gsonObjectMapperFactory(
                new GsonObjectMapperFactory() {
                    public Gson create(Class cls, String charset) {
                        return new GsonBuilder().setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
                    }
                }
        ));</code></pre>
<p>这里为GSON、JAXB、Jackson和Faster Jackson都预定义了用来映射实例的工厂。</p>
<h3 id="10-4-自定义"><a href="#10-4-自定义" class="headerlink" title="10-4.自定义"></a>10-4.自定义</h3><p>默认情况下rest-assured将会扫描classpath中各种各样的对象映射。如果您想要集成一种对象映射，默认是不支持的，如果您已经做好了封装，可以实现<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/mapper/ObjectMapper.html" target="_blank" rel="noopener">io.restassured.mapper.ObjectMapper</a> 接口。告诉rest-assured使用您的对象映射或者将其作为body方法里的第二个参数：</p>
<pre><code class="java">given().body(myJavaObject, myObjectMapper).when().post(&quot;..&quot;)</code></pre>
<p>或者您可以静态式定义：</p>
<pre><code class="java">RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig(myObjectMapper));</code></pre>
<p>更多例子参阅<a href="https://github.com/rest-assured/rest-assured/blob/master/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/CustomObjectMappingITest.java" target="_blank" rel="noopener">这里</a>。</p>
<h2 id="11-解析器"><a href="#11-解析器" class="headerlink" title="11.解析器"></a>11.解析器</h2><h3 id="11-1-自定义解析器"><a href="#11-1-自定义解析器" class="headerlink" title="11-1.自定义解析器"></a>11-1.自定义解析器</h3><p>rest-assured提供了预定义的解析器，例如HTML、XML和JSON的。但是您可以通过注册预置的解析器来解析现在不支持的内容类型：</p>
<pre><code class="java">RestAssured.registerParser(&lt;content-type&gt;, &lt;parser&gt;);</code></pre>
<p>例如注册一个可以解析’application/vnd.uoml+xml’类型的XML解析器：</p>
<pre><code class="java">RestAssured.registerParser(&quot;application/vnd.uoml+xml&quot;, Parser.XML);</code></pre>
<p>您也可以注销一个解析器：</p>
<pre><code class="java">RestAssured.unregisterParser(&quot;application/vnd.uoml+xml&quot;);</code></pre>
<p>解析器可以指定于每个请求中：</p>
<pre><code class="java">get(..).then().using().parser(&quot;application/vnd.uoml+xml&quot;, Parser.XML). ..;</code></pre>
<p>然后使用<a href="#模式复用">模式</a>。</p>
<h3 id="11-2-默认解析器"><a href="#11-2-默认解析器" class="headerlink" title="11-2.默认解析器"></a>11-2.默认解析器</h3><p>有时如果响应中不包含任何content-type，指定一个默认的解析器会很有用。</p>
<pre><code class="java">RestAssured.defaultParser = Parser.JSON;</code></pre>
<p>你也可以为一次请求指定默认的解析器：</p>
<pre><code class="java">get(&quot;/x&quot;).then().using().defaultParser(Parser.JSON). ..</code></pre>
<p>或者使用<a href="#模式复用">响应体模式</a>。</p>
<h2 id="12-默认值"><a href="#12-默认值" class="headerlink" title="12.默认值"></a>12.默认值</h2><p>rest-assured发起请求时默认使用localhost的8080端口.如果你需要换个端口：</p>
<pre><code class="java">given().port(80). ..</code></pre>
<p>或者简单些:</p>
<pre><code class="java">..when().get(&quot;http://myhost.org:80/doSomething&quot;);</code></pre>
<p>您也可以改变默认的基本URI、基本路径、端口和认证scheme：</p>
<pre><code class="java">RestAssured.baseURI = &quot;http://myhost.org&quot;;
RestAssured.port = 80;
RestAssured.basePath = &quot;/resource&quot;;
RestAssured.authentication = basic(&quot;username&quot;, &quot;password&quot;);
RestAssured.rootPath = &quot;x.y.z&quot;;</code></pre>
<p>这意味着类似<code>get(&quot;/hello&quot;)</code>这样的请求实际上会被解析为<a href="http://myhost.org:80/resource/hello，附带身份认证中的用户名和密码属性。关于设置根路径参考[这里](http://code.google.com/p/rest-assured/wiki/Usage#Root_path)。其它的默认值也可以被指定：" target="_blank" rel="noopener">http://myhost.org:80/resource/hello，附带身份认证中的用户名和密码属性。关于设置根路径参考[这里](http://code.google.com/p/rest-assured/wiki/Usage#Root_path)。其它的默认值也可以被指定：</a></p>
<pre><code class="java">RestAssured.filters(..); // List of default filters
RestAssured.requestSpecification = .. // Default request specification
RestAssured.responseSpecification = .. // Default response specification
RestAssured.urlEncodingEnabled = .. // Specify if Rest Assured should URL encoding the parameters
RestAssured.defaultParser = .. // Specify a default parser for response bodies if no registered parser can handle data of the response content-type
RestAssured.registerParser(..) // Specify a parser for the given content-type
RestAssured.unregisterParser(..) // Unregister a parser for the given content-type</code></pre>
<p>您可以设置重置为标准的baseURI (localhost)，basePath（空），标准端口（8080），标准根路径（“”），默认身份认证scheme（none）和URL编码启用（true）：</p>
<pre><code class="java">RestAssured.reset();</code></pre>
<h2 id="13-模式复用"><a href="#13-模式复用" class="headerlink" title="13.模式复用"></a>13.模式复用</h2><p>与其复制一份响应的断言或者请求参数（的代码）到另一个测试用例中，我们可以使用 <a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/builder/RequestSpecBuilder.html" target="_blank" rel="noopener">RequestSpecBuilder</a>或者<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/builder/ResponseSpecBuilder.html" target="_blank" rel="noopener">ResponseSpecBuilder</a>定义一个规范提案。</p>
<p>举个例子，在多个测试用例中，我们都涉及到这样的内容：判断响应码是否为200，JSON数组x.y的长度是否是2，您可以定义一个ResponseSpecBuilder：</p>
<pre><code class="java">ResponseSpecBuilder builder = new ResponseSpecBuilder();
builder.expectStatusCode(200);
builder.expectBody(&quot;x.y.size()&quot;, is(2));
ResponseSpecification responseSpec = builder.build();

// Now you can re-use the &quot;responseSpec&quot; in many different tests:
when().
       get(&quot;/something&quot;).
then().
       spec(responseSpec).
       body(&quot;x.y.z&quot;, equalTo(&quot;something&quot;));</code></pre>
<p>在这个例子中需要重用的数据定义并合并在”responseSpec”，并且仅当所有预期都通过时用例才能通过。</p>
<p>您也可以将相同的请求参数重用：</p>
<pre><code class="java">RequestSpecBuilder builder = new RequestSpecBuilder();
builder.addParam(&quot;parameter1&quot;, &quot;parameterValue&quot;);
builder.addHeader(&quot;header1&quot;, &quot;headerValue&quot;);
RequestSpecification requestSpec = builder.build();

given().
        spec(requestSpec).
        param(&quot;parameter2&quot;, &quot;paramValue&quot;).
when().
        get(&quot;/something&quot;).
then().
        body(&quot;x.y.z&quot;, equalTo(&quot;something&quot;));        </code></pre>
<p>这里请求数据合并在”requestSpec”中，由此上面例子中实际请求参数包括两个(“parameter1” 和 “parameter2”)和一个header(“header1”)。</p>
<h2 id="14-过滤器"><a href="#14-过滤器" class="headerlink" title="14.过滤器"></a>14.过滤器</h2><h3 id="14-1-Ordered-Filters"><a href="#14-1-Ordered-Filters" class="headerlink" title="14-1.Ordered Filters"></a>14-1.Ordered Filters</h3><p>过滤器会在请求实际发起之前侦测和改变该请求的内容，也可以在响应体实际返回之前拦截并<a href="#response-builder">改变</a>。您可以将其理解为AOP中的around advice（译者注：可以自行搜索切片编程）。过滤器也可以用在认证scheme、session管理、日志中。创建一个过滤器需要实现<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/filter/Filter.html" target="_blank" rel="noopener">io.restassured.filter.Filter</a>接口。使用过滤器：</p>
<pre><code class="java">given().filter(new MyFilter()). ..</code></pre>
<p>rest-assured提供了几个过滤器：</p>
<ol>
<li><code>io.restassured.filter.log.RequestLoggingFilter</code>: 可以打印出请求模式的细节。</li>
<li><code>io.restassured.filter.log.ResponseLoggingFilter</code>: 可以打印响应信息的细节如果响应体的状态码匹配given方法的参数。</li>
<li><code>io.restassured.filter.log.ErrorLoggingFilter</code>: 如果发生了异常（状态码在400和500之间），过滤器将会打印响应的内容。</li>
</ol>
<h3 id="14-2-Response-Builder"><a href="#14-2-Response-Builder" class="headerlink" title="14-2.Response Builder"></a>14-2.Response Builder</h3><p>如果您想要通过一个过滤器改变<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/Response.html" target="_blank" rel="noopener">Response</a> ，可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/builder/ResponseBuilder.html" target="_blank" rel="noopener">ResponseBuilder</a>创建一个基于原始response的新实例。比如把原始响应体改为something：</p>
<pre><code class="java">Response newResponse = new ResponseBuilder().clone(originalResponse).setBody(&quot;Something&quot;).build();</code></pre>
<h2 id="15-日志"><a href="#15-日志" class="headerlink" title="15.日志"></a>15.日志</h2><p>在大量的用例中，打印出响应或者请求的细节将有助于创建正确的预期、发送准确的请求。为此您可以使用rest-assured预定义的<a href="#过滤器">过滤器</a>，或者使用其中的快捷方法。</p>
<h3 id="15-1-请求日志"><a href="#15-1-请求日志" class="headerlink" title="15-1.请求日志"></a>15-1.请求日志</h3><p>自1.5版本起rest-assured支持对<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/specification/RequestSpecification.html" target="_blank" rel="noopener">特定的请求</a>打日志，之前的做法是使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/filter/log/RequestLoggingFilter.html" target="_blank" rel="noopener">RequestLoggingFilter（译者注：应该是通过过滤器进行控制）</a>。注意打印日志后HTTP Builder和HTTP Client会添加额外的header内容。这个过滤器可以只记录特定请求的特定细节。换句话说，你可以不关注<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/filter/log/RequestLoggingFilter.html" target="_blank" rel="noopener">RequestLoggingFilter</a>记录的有关实际往服务端发送的内容。因为随后的其它过滤器会在日志记录后改变这个请求。如果你想要记录实际发送的内容，参阅<a href="http://hc.apache.org/httpcomponents-client-ga/logging.html" target="_blank" rel="noopener">HTTP Client logging docs</a> or use an external tool such <a href="http://www.wireshark.org/" target="_blank" rel="noopener">Wireshark</a>，或者使用第三方工具例如<a href="http://www.wireshark.org/" target="_blank" rel="noopener">Wireshark</a>。示例如下：</p>
<pre><code class="java">given().log().all(). .. // Log all request specification details including parameters, headers and body
given().log().params(). .. // Log only the parameters of the request
given().log().body(). .. // Log only the request body
given().log().headers(). .. // Log only the request headers
given().log().cookies(). .. // Log only the request cookies
given().log().method(). .. // Log only the request method
given().log().path(). .. // Log only the request path</code></pre>
<h3 id="15-2-响应日志"><a href="#15-2-响应日志" class="headerlink" title="15-2.响应日志"></a>15-2.响应日志</h3><p>如果您想打印除了状态码以外的响应信息，可以：</p>
<pre><code class="java">get(&quot;/x&quot;).then().log().body() ..</code></pre>
<p>这样做，无论是否有异常错误发生，都会打印出响应信息。如果您希望只有当错误发生时才打印响应信息，可以：</p>
<pre><code class="java">get(&quot;/x&quot;).then().log().ifError(). .. </code></pre>
<p>您也可以记录响应里包括状态码、header、cookie的所有细节：</p>
<pre><code class="java">get(&quot;/x&quot;).then().log().all(). .. </code></pre>
<p>也可以只记录状态码、header或者cookie：</p>
<pre><code class="java">get(&quot;/x&quot;).then().log().statusLine(). .. // Only log the status line
get(&quot;/x&quot;).then().log().headers(). .. // Only log the response headers
get(&quot;/x&quot;).then().log().cookies(). .. // Only log the response cookies</code></pre>
<p>您也可以配置为仅当状态码匹配某个值时才打印响应体：</p>
<pre><code class="java">get(&quot;/x&quot;).then().log().ifStatusCodeIsEqualTo(302). .. // Only log if the status code is equal to 302
get(&quot;/x&quot;).then().log().ifStatusCodeMatches(matcher). .. // Only log if the status code matches the supplied Hamcrest matcher</code></pre>
<h3 id="15-3-认证失败日志"><a href="#15-3-认证失败日志" class="headerlink" title="15-3.认证失败日志"></a>15-3.认证失败日志</h3><p>自rest-assured2.3.1版本起，您可以仅当认证失败时记录请求或者响应的日志。为请求打日志：</p>
<pre><code class="java">given().log().ifValidationFails(). ..</code></pre>
<p>为响应打日志：</p>
<pre><code class="java">.. .then().log().ifValidationFails(). ..</code></pre>
<p>同时启用对请求和响应的认证失败记录，可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/LogConfig.html" target="_blank" rel="noopener">LogConfig</a>:</p>
<pre><code class="java">given().config(RestAssured.config().logConfig(logConfig().enableLoggingOfRequestAndResponseIfValidationFails(HEADERS))). ..</code></pre>
<p>认证失败，仅记录header。</p>
<p>还有种针对所有请求的简单写法：</p>
<pre><code class="java">RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();</code></pre>
<h3 id="15-4-黑名单日志"><a href="#15-4-黑名单日志" class="headerlink" title="15-4.黑名单日志"></a>15-4.黑名单日志</h3><p>As of REST Assured 4.2.0 it’s possible to blacklist headers so that they are not shown in the request or response log. Instead the header value will be replaced with [ BLACKLISTED ]. You can enable this per header basis using the LogConfig:</p>
<pre><code class="java">given().config(config().logConfig(logConfig().blacklistHeader(&quot;Accept&quot;))). ..</code></pre>
<p>The response log will the print:</p>
<pre><code class="txt">Request method:   GET
Request URI:    http://localhost:8080/something
Proxy:          &lt;none&gt;
Request params: &lt;none&gt;
Query params:   &lt;none&gt;
Form params:    &lt;none&gt;
Path params:    &lt;none&gt;
Headers:        Accept=[ BLACKLISTED ]
Cookies:        &lt;none&gt;
Multiparts:     &lt;none&gt;
Body:           &lt;none&gt;</code></pre>
<h2 id="16-根路径"><a href="#16-根路径" class="headerlink" title="16.根路径"></a>16.根路径</h2><p>为避免在body方法里使用重复的路径，您可以指定一个根路径：</p>
<pre><code class="java">when().
         get(&quot;/something&quot;).
then().
         body(&quot;x.y.firstName&quot;, is(..)).
         body(&quot;x.y.lastName&quot;, is(..)).
         body(&quot;x.y.age&quot;, is(..)).
         body(&quot;x.y.gender&quot;, is(..));</code></pre>
<p>使用根路径：</p>
<pre><code class="java">when().
        get(&quot;/something&quot;).
then().
         root(&quot;x.y&quot;). // You can also use the &quot;root&quot; method
         body(&quot;firstName&quot;, is(..)).
         body(&quot;lastName&quot;, is(..)).
         body(&quot;age&quot;, is(..)).
         body(&quot;gender&quot;, is(..));</code></pre>
<p>也可以设置一个默认的根路径：</p>
<pre><code class="java">RestAssured.rootPath = &quot;x.y&quot;;</code></pre>
<p>在许多高级用例中，在根路径上附加一些参数也很有用。您可以使用<code>appendRoot</code>方法：</p>
<pre><code class="java">when().
         get(&quot;/jsonStore&quot;).
then().
         root(&quot;store.%s&quot;, withArgs(&quot;book&quot;)).
         body(&quot;category.size()&quot;, equalTo(4)).
         appendRoot(&quot;%s.%s&quot;, withArgs(&quot;author&quot;, &quot;size()&quot;)).
         body(withNoArgs(), equalTo(4));</code></pre>
<p>也可以对根路径进行拆分：</p>
<pre><code class="java">when().
         get(&quot;/jsonStore&quot;).
then().
         root(&quot;store.category&quot;).
         body(&quot;size()&quot;, equalTo(4)).
         detachRoot(&quot;category&quot;).
         body(&quot;size()&quot;, equalTo(1));</code></pre>
<h3 id="16-1-路径参数"><a href="#16-1-路径参数" class="headerlink" title="16-1.路径参数"></a>16-1.路径参数</h3><p>在预定义的路径包含变量时，路径参数会很有用。举个例子：</p>
<pre><code class="java">String someSubPath = &quot;else&quot;;
int index = 1;
get(&quot;/x&quot;).then().body(&quot;something.%s[%d]&quot;, withArgs(someSubPath, index), equalTo(&quot;some value&quot;)). ..</code></pre>
<p>将会对”<code>something.else[0]（译者注：这里只是举个例子）</code>“是否等于”some value”进行判断。</p>
<p>另一种用法是，如果您有复杂的<a href="http://code.google.com/p/rest-assured/wiki/Usage#Root_path" target="_blank" rel="noopener">根路径</a>：</p>
<pre><code class="java">when().
       get(&quot;/x&quot;).
then().
       root(&quot;filters.filterConfig[%d].filterConfigGroups.find { it.name == &#39;GroupName&#39; }.includes&quot;).
       body(withArgs(0), hasItem(&quot;first&quot;)).
       body(withArgs(1), hasItem(&quot;second&quot;)).
       ..</code></pre>
<p>路径参数遵循Java的标准<a href="http://download.oracle.com/javase/1,5.0/docs/api/java/util/Formatter.html#syntax" target="_blank" rel="noopener">格式语法</a>。</p>
<p>注意<code>withArgs</code>方法可以从<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/RestAssured.html" target="_blank" rel="noopener">io.restassured.RestAssured</a>类中静态导入。</p>
<p>有时当所有在根路径中指定的参数都已经验证过了，只想要验证一个不含多余参数的body时，可以使用<code>withNoArgs</code>：</p>
<pre><code class="java">when().
         get(&quot;/jsonStore&quot;).
then().
         root(&quot;store.%s&quot;, withArgs(&quot;book&quot;)).
         body(&quot;category.size()&quot;, equalTo(4)).
         appendRoot(&quot;%s.%s&quot;, withArgs(&quot;author&quot;, &quot;size()&quot;)).
         body(withNoArgs(), equalTo(4));</code></pre>
<h2 id="17-Session支持"><a href="#17-Session支持" class="headerlink" title="17.Session支持"></a>17.Session支持</h2><p>rest-assured提供了一套简单的管理session的方式。您可以在DSL（译者注：领域特定语言）中预定义一个session的id值：</p>
<pre><code class="java">given().sessionId(&quot;1234&quot;). .. </code></pre>
<p>上面的代码实际上是这个的简写：</p>
<pre><code class="java">given().cookie(&quot;JSESSIONID&quot;, &quot;1234&quot;). .. </code></pre>
<p>您也可以为所有的请求指定一个默认的<code>sessionId</code>：</p>
<pre><code class="java">RestAssured.sessionId = &quot;1234&quot;;</code></pre>
<p>默认情况下session id的名字是<code>JSESSIONID</code>，但是您可以通过使用<a href="#session-config">SessionConfig</a>来修改：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().sessionConfig(new SessionConfig().sessionIdName(&quot;phpsessionid&quot;));</code></pre>
<p>您也可以指定一个sessionid并在其它用例中复用，使用<code>RequestSpecBuilder</code>：</p>
<pre><code class="java">RequestSpecBuilder spec = new RequestSpecBuilder().setSessionId(&quot;value1&quot;).build();

// Make the first request with session id equal to value1
given().spec(spec). .. 
// Make the second request with session id equal to value1
given().spec(spec). .. </code></pre>
<p>从响应对象中获取一个session id：</p>
<pre><code class="java">String sessionId = get(&quot;/something&quot;).sessionId();</code></pre>
<h3 id="17-1-Session过滤器"><a href="#17-1-Session过滤器" class="headerlink" title="17-1.Session过滤器"></a>17-1.Session过滤器</h3><p>2.0.0版本起您可以使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/filter/session/SessionFilter.html" target="_blank" rel="noopener">session filter</a>截获并提供一个session，举个例子：</p>
<pre><code class="java">SessionFilter sessionFilter = new SessionFilter();

given().
          auth().form(&quot;John&quot;, &quot;Doe&quot;).
          filter(sessionFilter).
when().
          get(&quot;/formAuth&quot;).
then().
          statusCode(200);


given().
          filter(sessionFilter). // Reuse the same session filter instance to automatically apply the session id from the previous response
when().
          get(&quot;/x&quot;).
then().
          statusCode(200);</code></pre>
<p>要想获取由<code>SessionFilter</code>截获的session id：</p>
<pre><code class="java">String sessionId = sessionFilter.getSessionId();</code></pre>
<h2 id="18-SSL"><a href="#18-SSL" class="headerlink" title="18.SSL"></a>18.SSL</h2><p>在多数场景下，SSL能顺利运转，这多亏于HTTP Builder和HTTP Client。如果服务端使用了无效的证书，然而有些例子下还是会出错。最简单的方法您可以使用”relaxed HTTPs validation”：</p>
<pre><code class="java">given().relaxedHTTPSValidation().when().get(&quot;https://some_server.com&quot;). .. </code></pre>
<p>也可以为所有的请求静态定义这个配置：</p>
<pre><code class="java">RestAssured.useRelaxedHTTPSValidation();</code></pre>
<p>或者放在请求指定中进行复用。</p>
<p>这将会假定我们使用SSL协议。想要改变需要覆盖<code>relaxedHTTPSValidation</code>方法：</p>
<pre><code class="java">given().relaxedHTTPSValidation(&quot;TLS&quot;).when().get(&quot;https://some_server.com&quot;). .. </code></pre>
<p>您也可以创建一个Java keystore文件并执行一些细粒度的操作。这并不难，首先阅读<a href="https://github.com/jgritman/httpbuilder/wiki/SSL" target="_blank" rel="noopener">指南</a>，然后在rest-assured中使用keystore：</p>
<pre><code class="java">given().keystore(&quot;/pathToJksInClassPath&quot;, &lt;password&gt;). .. </code></pre>
<p>或者为每一个请求指定：</p>
<pre><code class="java">RestAssured.keystore(&quot;/pathToJksInClassPath&quot;, &lt;password&gt;);</code></pre>
<p>您也可以定义一个<a href="http://code.google.com/p/rest-assured/wiki/Usage#Specification_Re-use" target="_blank" rel="noopener">可复用的</a>keystore。</p>
<p>如果您已经使用密码载入了一个keystore，可以将其作为可信的keystore：</p>
<pre><code class="java">RestAssured.trustStore(keystore);</code></pre>
<p>在<a href="https://github.com/rest-assured/rest-assured/blob/master/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/SSLTest.java" target="_blank" rel="noopener">这</a>也可以找到一些相关的示例。</p>
<p>有关更多SSL的高级配置参阅<a href="#ssl配置">SSL Configuration</a>。</p>
<h3 id="18-1-SSL无效主机名"><a href="#18-1-SSL无效主机名" class="headerlink" title="18-1.SSL无效主机名"></a>18-1.SSL无效主机名</h3><p>如果证书指定了一个无效的主机名，并且您无需创建和导入一个keystore。自2.2.0起您可以：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().sslConfig(sslConfig().allowAllHostnames());</code></pre>
<p>让所有请求支持所有的主机名。</p>
<pre><code class="java">given().config(RestAssured.config().sslConfig(sslConfig().allowAllHostnames()). .. ;</code></pre>
<p>对于单个请求。</p>
<p>注意如果您使用了”relaxed HTTPs validation”，那么<code>allowAllHostnames</code>将会默认启用。</p>
<h2 id="19-URL编码"><a href="#19-URL编码" class="headerlink" title="19.URL编码"></a>19.URL编码</h2><p>由于rest-assured提供了优秀的自动编码，通常您无需考虑URL编码的事情。在有些用例中仍然需要关闭URL编码的功能。其中一个原因是在使用rest-assured之前可能你已经做过一次编码。为防止两次URL编码您需要告诉rest-assured禁用这个功能。</p>
<pre><code class="java">String response = given().urlEncodingEnabled(false).get(&quot;https://jira.atlassian.com:443/rest/api/2.0.alpha1/search?jql=project%20=%20BAM%20AND%20issuetype%20=%20Bug&quot;).asString();
..</code></pre>
<p>或者</p>
<pre><code class="java">RestAssured.baseURI = &quot;https://jira.atlassian.com&quot;;
RestAssured.port = 443;
RestAssured.urlEncodingEnabled = false;
final String query = &quot;project%20=%20BAM%20AND%20issuetype%20=%20Bug&quot;;
String response = get(&quot;/rest/api/2.0.alpha1/search?jql={q}&quot;, query);
..</code></pre>
<h2 id="20-代理配置"><a href="#20-代理配置" class="headerlink" title="20.代理配置"></a>20.代理配置</h2><p>从版本2.3.2开始REST Assured可以更好地支持代理。 例如，如果你有一个代理在localhost端口8888你可以做：</p>
<pre><code class="java">given().proxy(&quot;localhost&quot;, 8888). .. </code></pre>
<p>如果服务器在本地环境中运行，可以不指定主机名：</p>
<pre><code class="java">given().proxy(8888). .. // Will assume localhost</code></pre>
<p>要使用HTTPS，需要提供第三个参数（scheme）或使用<code>io.restassured.specification.ProxySpecification</code>。 例如：</p>
<pre><code class="java">given().proxy(host(&quot;localhost&quot;).withScheme(&quot;https&quot;)). ..</code></pre>
<p>其中host从io.restassured.specification.ProxySpecification静态导入。</p>
<p>从版本2.7.0开始，您还可以为代理指定抢占式基本身份验证。 例如：</p>
<pre><code>given().proxy(auth(&quot;username&quot;, &quot;password&quot;)).when() ..</code></pre><p>其中<code>auth</code>是从<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/specification/ProxySpecification.html" target="_blank" rel="noopener">io.restassured.specification.ProxySpecification</a>静态导入的，也可以将身份验证与不同的host相结合：</p>
<pre><code class="java">given().proxy(host(&quot;http://myhost.org&quot;).withAuth(&quot;username&quot;, &quot;password&quot;)). ..</code></pre>
<h3 id="20-1-静态代理配置"><a href="#20-1-静态代理配置" class="headerlink" title="20-1.静态代理配置"></a>20-1.静态代理配置</h3><p>可以为所有请求配置静态代理，例如：</p>
<pre><code class="java">RestAssured.proxy(&quot;localhost&quot;, 8888);    </code></pre>
<p>或者：</p>
<pre><code class="java">RestAssured.proxy = host(&quot;localhost&quot;).withPort(8888);</code></pre>
<h3 id="20-2-请求规范代理配置"><a href="#20-2-请求规范代理配置" class="headerlink" title="20-2.请求规范代理配置"></a>20-2.请求规范代理配置</h3><p>您还可以创建请求规范并在其中指定代理：</p>
<pre><code class="java">RequestSpecification specification = new RequestSpecBuilder().setProxy(&quot;localhost&quot;).build();
given().spec(specification). ..</code></pre>
<h2 id="21-详细配置"><a href="#21-详细配置" class="headerlink" title="21.详细配置"></a>21.详细配置</h2><p>详细配置由<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/RestAssuredConfig.html" target="_blank" rel="noopener">RestAssuredConfig</a>实例提供，您可以使用它配置<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/HttpClientConfig.html" target="_blank" rel="noopener">HTTP Client</a>的参数以及<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/RedirectConfig.html" target="_blank" rel="noopener">重定向</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/LogConfig.html" target="_blank" rel="noopener">日志</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/EncoderConfig.html" target="_blank" rel="noopener">编码器</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/DecoderConfig.html" target="_blank" rel="noopener">解码器</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/SessionConfig.html" target="_blank" rel="noopener">Session</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/ObjectMapperConfig.html" target="_blank" rel="noopener">ObjectMapper</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/ConnectionConfig.html" target="_blank" rel="noopener">Connection</a>，<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/SSLConfig.html" target="_blank" rel="noopener">SSL</a>和<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/ParamConfig.html" target="_blank" rel="noopener">ParamConfig</a> 设置。 例子：</p>
<p>特定请求:</p>
<pre><code class="java">given().config(RestAssured.config().redirect(redirectConfig().followRedirects(false))). ..</code></pre>
<p>或使用RequestSpecBuilder：</p>
<pre><code class="java">RequestSpecification spec = new RequestSpecBuilder().setConfig(RestAssured.config().redirect(redirectConfig().followRedirects(false))).build();</code></pre>
<p>或所有请求：</p>
<pre><code class="java">RestAssured.config = config().redirect(redirectConfig().followRedirects(true).and().maxRedirects(0));</code></pre>
<p><code>config()</code> and <code>newConfig()</code> can be statically imported from <code>io.restassured.config.RestAssuredConfig</code>.</p>
<h3 id="21-1-编码配置"><a href="#21-1-编码配置" class="headerlink" title="21-1.编码配置"></a>21-1.编码配置</h3><p>使用[EncoderConfig]（<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/EncoderConfig.html），可以指定默认的内容encoding" target="_blank" rel="noopener">http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/EncoderConfig.html），可以指定默认的内容encoding</a> charset（如果没有在content-type头中指定）和查询参数charset为所有请求。 如果未指定内容字符集，则使用ISO-8859-1，如果未指定查询参数字符集，则使用UTF-8。 用法示例：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().encoderConfig(encoderConfig().defaultContentCharset(&quot;US-ASCII&quot;));</code></pre>
<p>如果没有通过使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/EncoderConfig.html" target="_blank" rel="noopener">EncoderConfig</a>中的defaultCharsetForContentType方法为此内容类型显式定义字符集，那么还可以指定用于特定内容类型的编码器字符集。 例如：</p>
<pre><code class="java">RestAssured.config = RestAssured.config(config().encoderConfig(encoderConfig().defaultCharsetForContentType(&quot;UTF-16&quot;, &quot;application/xml&quot;)));</code></pre>
<p>这将假设明确指定一个字符集的“application / xml”内容类型的UTF-16编码。 默认情况下，“application / json”被指定为使用“UTF-8”作为默认内容类型，这是由[RFC4627]（<a href="https://www.ietf.org/rfc/rfc4627.txt）指定的。" target="_blank" rel="noopener">https://www.ietf.org/rfc/rfc4627.txt）指定的。</a></p>
<p><strong>避免自动将字符集添加到content-type标头</strong></p>
<p>默认情况下，REST Assured会自动添加字符集标头。 要完全禁用这个，你可以这样配置<code>EncoderConfig</code>：</p>
<pre><code class="java">RestAssured.config = RestAssured.config(config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false));</code></pre>
<h3 id="21-2-解码配置"><a href="#21-2-解码配置" class="headerlink" title="21-2.解码配置"></a>21-2.解码配置</h3><p>使用[DecoderConfig]（<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/DecoderConfig.html），您可以将默认响应内容解码字符集设置为" target="_blank" rel="noopener">http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/DecoderConfig.html），您可以将默认响应内容解码字符集设置为</a> 所有响应。 如果您期望使用不同于ISO-8859-1的内容字符集（这是默认字符集），并且响应未在内容类型标头中定义字符集，那么这将非常有用。 用法示例：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().decoderConfig(decoderConfig().defaultContentCharset(&quot;UTF-8&quot;));</code></pre>
<p>您还可以使用“DecoderConfig”来指定要应用哪些内容解码器。 当你这样做时，“Accept-Encoding”头部将被自动添加到请求中，并且响应主体将被自动解码。 默认情况下，启用GZIP和DEFLATE解码器。 例如要删除GZIP解码但保留DEFLATE解码，您可以执行以下操作：<br>您还可以使用“DecoderConfig”来指定要应用哪些内容解码器。 当你这样做时，“Accept-Encoding”头部将被自动添加到请求中，并且响应主体将被自动解码。 默认情况下，启用GZIP和DEFLATE解码器。 例如要删除GZIP解码但保留DEFLATE解码，您可以执行以下操作：</p>
<pre><code class="java">given().config(RestAssured.config().decoderConfig(decoderConfig().contentDecoders(DEFLATE))). ..</code></pre>
<p>如果没有通过使用<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/DecoderConfig.html" target="_blank" rel="noopener">DecoderConfig</a>中的“defaultCharsetForContentType”方法为此内容类型明确定义字符集，则还可以指定要用于特定内容类型的解码器字符集。 例如：</p>
<pre><code class="java">RestAssured.config = config(config().decoderConfig(decoderConfig().defaultCharsetForContentType(&quot;UTF-16&quot;, &quot;application/xml&quot;)));</code></pre>
<p>这将假设明确指定一个字符集的“application / xml”内容类型的UTF-16编码。 默认情况下，“application / json”使用“UTF-8”作为默认字符集，这是由[RFC4627]（<a href="https://www.ietf.org/rfc/rfc4627.txt）指定的。" target="_blank" rel="noopener">https://www.ietf.org/rfc/rfc4627.txt）指定的。</a></p>
<h3 id="21-3-Session配置"><a href="#21-3-Session配置" class="headerlink" title="21-3.Session配置"></a>21-3.Session配置</h3><p>使用Session配置，您可以配置REST Assured使用的默认session ID名称。 默认session id名称是<code>JSESSIONID</code>，如果应用程序中的名称不同，并且您希望使用REST Assured的[会话支持]（＃Session_support），您只需更改它。 用法：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().sessionConfig(new SessionConfig().sessionIdName(&quot;phpsessionid&quot;));</code></pre>
<h3 id="21-3-重定向-DSL"><a href="#21-3-重定向-DSL" class="headerlink" title="21-3.重定向 DSL"></a>21-3.重定向 DSL</h3><p>重定向配置可以使用DSL指定。 例如。</p>
<pre><code class="java">given().redirects().max(12).and().redirects().follow(true).when(). .. </code></pre>
<h3 id="21-4-网络连接配置"><a href="#21-4-网络连接配置" class="headerlink" title="21-4.网络连接配置"></a>21-4.网络连接配置</h3><p>让您配置REST Assured的连接设置。 例如，如果要在每个响应后强制关闭Apache HTTP Client连接。 如果您在响应中使用少量数据进行大量快速连续请求，则可能需要执行此操作。然而，如果你正在下载（尤其是大量的）分块，你绝不能每个响应后关闭连接的数据。 默认情况下，连接在每个响应后不关闭。</p>
<pre><code class="java">RestAssured.config = RestAssured.config().connectionConfig(connectionConfig().closeIdleConnectionsAfterEachResponse());</code></pre>
<h3 id="21-5-Json-Config"><a href="#21-5-Json-Config" class="headerlink" title="21-5.Json Config"></a>21-5.Json Config</h3><p><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/path/json/config/JsonPathConfig.html" target="_blank" rel="noopener">JsonPathConfig</a>允许您在REST Assured或 <a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/path/json/JsonPath.html" target="_blank" rel="noopener">JsonPath</a>使用时配置Json设置。 它让你配置如何处理JSON数字。</p>
<pre><code class="java">RestAssured.config = RestAssured.config().jsonConfig(jsonConfig().numberReturnType(NumberReturnType.BIG_DECIMAL))</code></pre>
<h3 id="21-6-HTTP-Client配置"><a href="#21-6-HTTP-Client配置" class="headerlink" title="21-6.HTTP Client配置"></a>21-6.HTTP Client配置</h3><p>为REST Assured将在执行请求时使用的HTTP Client实例配置属性。 默认情况下，REST Assured会为每个“given”语句创建一个新的http Client实例。 要配置重用，请执行以下操作：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().httpClient(httpClientConfig().reuseHttpClientInstance());</code></pre>
<p>您还可以使用<code>httpClientFactory</code>方法提供自定义HTTP Client实例，例如：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().httpClient(httpClientConfig().httpClientFactory(
         new HttpClientConfig.HttpClientFactory() {

            @Override
            public HttpClient createHttpClient() {
                return new SystemDefaultHttpClient();
            }
        }));</code></pre>
<p><strong>注意，目前你需要提供一个<code>AbstractHttpClient</code>的实例.</strong></p>
<p>也可以配置默认参数等。</p>
<h3 id="21-7-SSL配置"><a href="#21-7-SSL配置" class="headerlink" title="21-7.SSL配置"></a>21-7.SSL配置</h3><p><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/SSLConfig.html" target="_blank" rel="noopener">SSLConfig</a> 允许您指定更高级的SSL配置，如信任库，密钥库类型和主机名验证器。 例如：</p>
<pre><code class="java">RestAssured.config = RestAssured.config().sslConfig(sslConfig().with().keystoreType(&lt;type&gt;).and().strictHostnames());</code></pre>
<h3 id="21-8-参数配置"><a href="#21-8-参数配置" class="headerlink" title="21-8.参数配置"></a>21-8.参数配置</h3><p><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/config/ParamConfig.html" target="_blank" rel="noopener">ParamConfig</a> 允许您配置在“冲突”时，更新不同的参数。 默认情况下，所有参数都将合并，因此如果您执行以下操作：</p>
<pre><code class="java">given().queryParam(&quot;param1&quot;, &quot;value1&quot;).queryParam(&quot;param1&quot;, &quot;value2&quot;).when().get(&quot;/x&quot;). ...</code></pre>
<p>REST Assured将发送一个查询字符串<code>param1 = value1＆param1 = value2</code>。<br>如果这不是您想要的，你可以配置REST Assured为* replace *值代替：</p>
<pre><code class="java">given().
        config(config().paramConfig(paramConfig().queryParamsUpdateStrategy(REPLACE))).
        queryParam(&quot;param1&quot;, &quot;value1&quot;).
        queryParam(&quot;param1&quot;, &quot;value2&quot;).
when().
        get(&quot;/x&quot;). ..</code></pre>
<p>REST Assured现在将替换<code>param1</code>的值为<code>value2</code>（因为它是最后写的），而不是将它们合并在一起。 您也可以为所有参数类型的每种类型配置统一的更新策略</p>
<pre><code class="java">given().config(config().paramConfig(paramConfig().replaceAllParameters())). ..</code></pre>
<p>也支持在[Spring Mock Mvc模块]（# Spring Mock Mvc 模块）（配置[MockMvcParamConfig]（<a href="http://static.javadoc.io/io.restassured/spring-mock" target="_blank" rel="noopener">http://static.javadoc.io/io.restassured/spring-mock</a> -mvc / 3.0.1 / io / restassured / module / mockmvc / config / MockMvcParamConfig.html）。</p>
<h3 id="21-10-失败配置"><a href="#21-10-失败配置" class="headerlink" title="21-10.失败配置"></a>21-10.失败配置</h3><p>Added in version 3.3.0 the FailureConfig can be used to get callbacks when REST Assured validation fails. This is useful if you want to do some custom logging or store data available in the request/response specification or in the response itself somewhere. For example let’s say that you want to be notified by email when the following test case fails because the status code is not 200:</p>
<pre><code class="java">given().
    param(&quot;x&quot;, &quot;y&quot;)
when().
    get(&quot;/hello&quot;)
then().
    statusCode(200);</code></pre>
<p>You can then implement a <a href="http://static.javadoc.io/io.rest-assured/rest-assured/4.3.0/io/restassured/listener/ResponseValidationFailureListener.html" target="_blank" rel="noopener">ResponseValidationFailureListener</a> and add it to the <a href="http://static.javadoc.io/io.rest-assured/rest-assured/4.3.0/io/restassured/config/FailureConfig.html" target="_blank" rel="noopener">FailureConfig</a>:</p>
<pre><code class="java">ResponseValidationFailureListener emailOnFailure = (reqSpec, respSpec, resp) -&gt; emailService.sendEmail(&quot;email@gmail.com&quot;, &quot;Important test failed! Status code was: &quot; + resp.statusCode());

given().
    config(RestAssured.config().failureConfig(failureConfig().with().failureListeners(emailOnFailure))).
    param(&quot;x&quot;, &quot;y&quot;)
when().
    get(&quot;/hello&quot;)
then().
    statusCode(200);</code></pre>
<h2 id="22-Spring-Mock-Mvc-模块"><a href="#22-Spring-Mock-Mvc-模块" class="headerlink" title="22.Spring Mock Mvc 模块"></a>22.Spring Mock Mvc 模块</h2><p>REST Assured 2.2.0引入了对[Spring Mock Mvc]（<a href="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.html）的支持，使用" target="_blank" rel="noopener">http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.html）的支持，使用</a> <code>spring-mock-mvc</code>模块。 这意味着您可以单元测试Spring Mvc控制器。 例如给出以下Spring控制器：</p>
<pre><code class="java">@Controller
public class GreetingController {

    private static final String template = &quot;Hello, %s!&quot;;
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping(value = &quot;/greeting&quot;, method = GET)
    public @ResponseBody Greeting greeting(
            @RequestParam(value=&quot;name&quot;, required=false, defaultValue=&quot;World&quot;) String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}</code></pre>
<p>你可以使用[RestAssuredMockMvc]（<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/RestAssuredMockMvc.html）来测试它，像这样：" target="_blank" rel="noopener">http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/RestAssuredMockMvc.html）来测试它，像这样：</a></p>
<pre><code class="java">given().
        standaloneSetup(new GreetingController()).
        param(&quot;name&quot;, &quot;Johan&quot;).
when().
        get(&quot;/greeting&quot;).
then().
        statusCode(200).
        body(&quot;id&quot;, equalTo(1)).
        body(&quot;content&quot;, equalTo(&quot;Hello, Johan!&quot;));  </code></pre>
<p>即它与标准的REST Assured语法非常相似。 这使得运行测试真的很快，并且比标准的REST Assured更容易引导环境和使用mock。 你常用的标准REST Assured中的大多数东西都可以使用RestAssured Mock Mvc。 例如（某些）配置，静态规范，日志等等。要使用它，你需要依赖于Spring Mock Mvc模块：</p>
<pre><code class="xml">&lt;dependency&gt;
      &lt;groupId&gt;io.rest-assured&lt;/groupId&gt;
      &lt;artifactId&gt;spring-mock-mvc&lt;/artifactId&gt;
      &lt;version&gt;3.0.1&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p>或者[下载]（<a href="http://dl.bintray.com/johanhaleby/generic/spring-mock-mvc-3.0.1-dist.zip）。" target="_blank" rel="noopener">http://dl.bintray.com/johanhaleby/generic/spring-mock-mvc-3.0.1-dist.zip）。</a></p>
<h3 id="22-1-Bootstrapping-RestAssuredMockMvc"><a href="#22-1-Bootstrapping-RestAssuredMockMvc" class="headerlink" title="22-1.Bootstrapping RestAssuredMockMvc"></a>22-1.Bootstrapping RestAssuredMockMvc</h3><p>静态导入方法:</p>
<pre><code class="java">io.restassured.module.mockmvc.RestAssuredMockMvc.*
io.restassured.module.mockmvc.matcher.RestAssuredMockMvcMatchers.*</code></pre>
<p>有关其他静态导入，请参阅文档的[静态导入]（＃static-imports）部分。</p>
<p>为了使用RestAssuredMockMvc启动测试，您需要使用一组控制器，MockMvc实例或Spring的WebApplicationContext来初始化它。您可以对单个请求执行此操作，如上例所示：</p>
<pre><code class="java">given().standaloneSetup(new GreetingController()). ..</code></pre>
<p>也可以使用静态方法:</p>
<pre><code class="java">RestAssuredMockMvc.standaloneSetup(new GreetingController());</code></pre>
<p>如果静态定义，则不必在DSL中指定任何控制器（或MockMvc或WebApplicationContext实例）。这意味着前面的例子可以写成：</p>
<pre><code class="java">given().
        param(&quot;name&quot;, &quot;Johan&quot;).
when().
        get(&quot;/greeting&quot;).
then().
        statusCode(200).
        body(&quot;id&quot;, equalTo(1)).
        body(&quot;content&quot;, equalTo(&quot;Hello, Johan!&quot;));  </code></pre>
<h3 id="22-2-异步请求"><a href="#22-2-异步请求" class="headerlink" title="22-2.异步请求"></a>22-2.异步请求</h3><p>从版本<code>2.5.0</code> RestAssuredMockMvc支持异步请求。例如，假设有以下控制器</p>
<pre><code class="java">@Controller
public class PostAsyncController {

    @RequestMapping(value = &quot;/stringBody&quot;, method = POST)
    public @ResponseBody
    Callable&lt;String&gt; stringBody(final @RequestBody String body) {
        return new Callable&lt;String&gt;() {
            public String call() throws Exception {
                return body;
            }
        };
    }
}</code></pre>
<p>你可以这样测试：</p>
<pre><code class="java">given().
        body(&quot;a string&quot;).
when().
        async().post(&quot;/stringBody&quot;).
then().
        body(equalTo(&quot;a string&quot;));</code></pre>
<p>默认超时为1秒。也可以使用DSL更改超时：</p>
<pre><code class="java">given().
        body(&quot;a string&quot;).
when().
        async().with().timeout(20, TimeUnit.SECONDS).post(&quot;/stringBody&quot;).
then().
        body(equalTo(&quot;a string&quot;));    </code></pre>
<p>还可以使用<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/2.4.1/io/restassured/module/mockmvc/config/AsyncConfig.html" target="_blank" rel="noopener">AsyncConfig</a>），例如：</p>
<pre><code class="java">given().
        config(config().asyncConfig(withTimeout(100, TimeUnit.MILLISECONDS))).
        body(&quot;a string&quot;).
when().
        async().post(&quot;/stringBody&quot;).
then().
        body(equalTo(&quot;a string&quot;));</code></pre>
<p><code>withTimeout</code>是从<code>io.restassured.module.mockmvc.config.AsyncConfig</code>静态导入的，只是创建一个具有给定超时的<code>AsyncConfig</code>的快捷方式。全局应用配置以应用于所有请求：</p>
<pre><code class="java">RestAssuredMockMvc.config = RestAssuredMockMvc.config().asyncConfig(withTimeout(100, TimeUnit.MILLISECONDS));

// Request 1
given().
        body(&quot;a string&quot;).
when().
        async().post(&quot;/stringBody&quot;).
then().
        body(equalTo(&quot;a string&quot;));

// Request 2
given().
        body(&quot;another string&quot;).
when().
        async().post(&quot;/stringBody&quot;).
then().
        body(equalTo(&quot;a string&quot;));</code></pre>
<p>请求1和2现在将使用默认超时100毫秒。</p>
<h3 id="22-3-添加请求后处理器"><a href="#22-3-添加请求后处理器" class="headerlink" title="22-3.添加请求后处理器"></a>22-3.添加请求后处理器</h3><p>Spring MockMvc已经对<a href="http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/request/RequestPostProcessor.html" target="_blank" rel="noopener">请求后处理器</a>做了支持，并且您也可以在RestAssuredMockMvc中使用。举个例子：</p>
<pre><code class="java">given().postProcessors(myPostProcessor1, myPostProcessor2). ..</code></pre>
<p>请注意，推荐从<code>org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors</code>(例如认证相关的 <code>RequestPostProcessors</code>)加入请求后处理器时，直接使用<code>auth</code>方法，这样可读性更强，当然结果是一样的：</p>
<pre><code class="java">given().auth().with(httpBasic(&quot;username&quot;, &quot;password&quot;)). ..</code></pre>
<p>这里的httpBasic静态导入自<a href="http://docs.spring.io/autorepo/docs/spring-security/current/apidocs/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.html" target="_blank" rel="noopener">SecurityMockMvcRequestPostProcessor</a>。</p>
<h3 id="22-4-添加结果处理器"><a href="#22-4-添加结果处理器" class="headerlink" title="22-4.添加结果处理器"></a>22-4.添加结果处理器</h3><p>Spring MockMvc对<a href="http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/ResultHandler.html" target="_blank" rel="noopener">结果处理器</a> 做了支持，您也可以在RestAssuredMockMvc中使用。比方说您想要使用原生的MockMvc日志功能：</p>
<pre><code class="java">.. .then().apply(print()). .. </code></pre>
<p>这里的<code>print</code>静态导入自<code>org.springframework.test.web.servlet.result.MockMvcResultHandlers</code>。请注意如果您正在使用2.6.0或更早版本的rest-assured，需要这样使用结果处理器：</p>
<pre><code class="java">given().resultHandlers(print()). .. </code></pre>
<p>但是rest-assured2.8.0起不推荐使用这种语法。</p>
<h3 id="22-5-使用结果匹配器"><a href="#22-5-使用结果匹配器" class="headerlink" title="22-5.使用结果匹配器"></a>22-5.使用结果匹配器</h3><p>Spring MockMvc提供了许多<a href="http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/ResultMatcher.html" target="_blank" rel="noopener">结果匹配器</a>，您可以从中获益。RestAssuredMockMvc也对其中必要的功能进行支持。举个例子，基于某种原因您想要使用结果匹配器验证状态码是否等于200：</p>
<pre><code class="java">given().
        param(&quot;name&quot;, &quot;Johan&quot;).
when().
        get(&quot;/greeting&quot;).
then().
        assertThat(status().isOk()).
        body(&quot;id&quot;, equalTo(1)).
        body(&quot;content&quot;, equalTo(&quot;Hello, Johan!&quot;));  </code></pre>
<p>这里的<code>status</code>静态导入自<code>org.springframework.test.web.servlet.result.MockMvcResultMatchers</code>。注意，您可以使用<code>expect</code>方法，功能上和<code>assertThat</code>一样，但是更接近原生的MockMvc的语法。</p>
<h3 id="22-5-拦截器"><a href="#22-5-拦截器" class="headerlink" title="22-5.拦截器"></a>22-5.拦截器</h3><p>您也可以在请求（译者注：这里指mock请求）曝光之前截住并改变<a href="http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.html" target="_blank" rel="noopener">MockHttpServletRequestBuilder</a>。您需要先定义一个<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/intercept/MockHttpServletRequestBuilderInterceptor.html" target="_blank" rel="noopener">MockHttpServletRequestBuilderInterceptor</a>，并在RestAssuredMockMvc中使用：</p>
<pre><code class="java">given().interceptor(myInterceptor). ..</code></pre>
<h3 id="22-6-Specifications"><a href="#22-6-Specifications" class="headerlink" title="22-6.Specifications"></a>22-6.Specifications</h3><p>正如标准的Rest Assured，你可以使用<a href="#specification_re-use">specifications</a>，以便更好地重用。请注意，RestAssuredMockMvc的请求规范构建器称为<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/specification/MockMvcRequestSpecBuilder.html" target="_blank" rel="noopener">MockMvcRequestSpecBuilder</a>。同样的<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/builder/ResponseSpecBuilder.html" target="_blank" rel="noopener">ResponseSpecBuilder</a> 也可以在RestAssuredMockMvc中使用。规格可以静态定义，就像标准的Res​​t Assured一样。例如：</p>
<pre><code class="java">RestAssuredMockMvc.requestSpecification = new MockMvcRequestSpecBuilder().addQueryParam(&quot;name&quot;, &quot;Johan&quot;).build();
RestAssuredMockMvc.responseSpecification = new ResponseSpecBuilder().expectStatusCode(200).expectBody(&quot;content&quot;, equalTo(&quot;Hello, Johan!&quot;)).build();

given().
        standaloneSetup(new GreetingController()).
when().
        get(&quot;/greeting&quot;).
then().
        body(&quot;id&quot;, equalTo(1));</code></pre>
<h3 id="22-7-重置-RestAssuredMockMvc"><a href="#22-7-重置-RestAssuredMockMvc" class="headerlink" title="22-7.重置 RestAssuredMockMvc"></a>22-7.重置 RestAssuredMockMvc</h3><p>如果您使用了任何静态配置，您可以通过调用RestAssuredMockMvc.reset（）方法轻松地将RestAssuredMockMvc重置为其默认状态。</p>
<h3 id="22-8-Spring-MVC认证"><a href="#22-8-Spring-MVC认证" class="headerlink" title="22-8.Spring MVC认证"></a>22-8.Spring MVC认证</h3><p><code>spring-mock-mvc</code>的版本`2.3.0’支持身份验证。例如：</p>
<pre><code class="java">given().auth().principal(..). ..</code></pre>
<p>一些认证方法需要Spring安全在类路径（可选）。也可以静态定义认证：</p>
<pre><code class="java">RestAssuredMockMvc.authentication = principal(&quot;username&quot;, &quot;password&quot;);</code></pre>
<p>其中<code>principal</code>方法是从<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/RestAssuredMockMvc.html" target="_blank" rel="noopener">RestAssuredMockMvc</a>静态导入的。还可以在请求构建器中定义认证方案：</p>
<pre><code class="java">MockMvcRequestSpecification spec = new MockMvcRequestSpecBuilder.setAuth(principal(&quot;username&quot;, &quot;password&quot;)).build();</code></pre>
<h4 id="22-8-1-使用-Spring-Security测试"><a href="#22-8-1-使用-Spring-Security测试" class="headerlink" title="22-8-1.使用 Spring Security测试"></a>22-8-1.使用 Spring Security测试</h4><p>从版本<code>2.5.0</code>也有更好的支持Spring Security。如果你在类路径中有<code>spring-security-test</code>，你可以这样做：</p>
<pre><code class="java">given().auth().with(httpBasic(&quot;username&quot;, &quot;password&quot;)). ..</code></pre>
<p>其中<code>httpBasic</code>是从<a href="http://docs.spring.io/autorepo/docs/spring-security/current/apidocs/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.html" target="_blank" rel="noopener">SecurityMockMvcRequestPostProcessor</a>静态导入的。这将对请求应用基本认证。为了这个工作，你需要应用<a href="http://docs.spring.io/autorepo/docs/spring-security/current/apidocs/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurers.html" target="_blank" rel="noopener">SecurityMockMvcConfigurer</a>到MockMvc实例。您可以手动执行此操作：</p>
<pre><code class="java">MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).apply(SecurityMockMvcConfigurers.springSecurity()).build();</code></pre>
<p>or RESTAssuredMockMvc will automatically try to apply the <code>springSecurity</code> configurer automatically if you initalize it with an instance of <a href="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.html" target="_blank" rel="noopener">AbstractMockMvcBuilder</a>, for example when configuring a “web app context”:</p>
<pre><code class="java">given().webAppContextSetup(context).auth().with(httpBasic(&quot;username&quot;, &quot;password&quot;)). ..</code></pre>
<p>Here’s a full example:</p>
<pre><code class="java">import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;

import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfiguration.class)
@WebAppConfiguration
public class BasicAuthExample {

    @Autowired
    private WebApplicationContext context;

    @Before public void
    rest_assured_is_initialized_with_the_web_application_context_before_each_test() {
        RestAssuredMockMvc.webAppContextSetup(context);
    }

    @After public void
    rest_assured_is_reset_after_each_test() {
        RestAssuredMockMvc.reset();
    }

    @Test public void
    basic_auth_example() {
        given().
                auth().with(httpBasic(&quot;username&quot;, &quot;password&quot;)).
        when().
                get(&quot;/secured/x&quot;).
        then().
                statusCode(200).
                expect(authenticated().withUsername(&quot;username&quot;));
    }
}</code></pre>
<p>You can also define authentication for all request, for example:</p>
<pre><code class="java">RestAssuredMockMvc.authentication = with(httpBasic(&quot;username&quot;, &quot;password&quot;));</code></pre>
<p>where <code>with</code> is statically imported from <code>io.restassured.module.mockmvc.RestAssuredMockMvc</code>. It’s also possible to use a <a href="#specifications">request specification</a>.</p>
<h4 id="22-8-2-注入一个用户"><a href="#22-8-2-注入一个用户" class="headerlink" title="22-8-2.注入一个用户"></a>22-8-2.注入一个用户</h4><p>也可以使用Spring Security测试注释，例如<a href="http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#test-method-withmockuser" target="_blank" rel="noopener">@WithMockUser</a>和 <a href="http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#test-method-withuserdetails" target="_blank" rel="noopener">@WithUserDetails</a>。例如，假设您想测试此控制器：</p>
<pre><code class="java">@Controller
public class UserAwareController {

    @RequestMapping(value = &quot;/user-aware&quot;, method = GET)
    public
    @ResponseBody
    String userAware(@AuthenticationPrincipal User user) {
        if (user == null || !user.getUsername().equals(&quot;authorized_user&quot;)) {
            throw new IllegalArgumentException(&quot;Not authorized&quot;);
        }

        return &quot;Success&quot;);
    }
}</code></pre>
<p>您可以看到`userAware’方法需要一个 <a href="http://docs.spring.io/autorepo/docs/spring-security/current/apidocs/org/springframework/security/core/userdetails/User.html" target="_blank" rel="noopener">User</a> 作为参数，我们让Spring Security使用<a href="http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/web/bind/annotation/AuthenticationPrincipal.html" target="_blank" rel="noopener">@AuthenticationPrincipal</a> 注入它。要生成测试用户，我们可以这样做：</p>
<pre><code class="java">@WithMockUser(username = &quot;authorized_user&quot;)
@Test public void
spring_security_mock_annotations_example() {
    given().
            webAppContextSetup(context).
     when().
            get(&quot;/user-aware&quot;).
     then().
            statusCode(200).
            body(equalTo(&quot;Success&quot;)).
            expect(authenticated().withUsername(&quot;authorized_user&quot;));
}</code></pre>
<p>注意，也可以不使用注释，而是使用<a href="http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/request/RequestPostProcessor.html" target="_blank" rel="noopener">RequestPostProcessor</a> ，例如<a href="http://docs.spring.io/autorepo/docs/spring-security/4.0.0.RELEASE/apidocs/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.html#user(java.lang.String)" target="_blank" rel="noopener">SecurityMockMvcRequestPostProcessors#user(java.lang.String)</a>.</p>
<p><strong>参数相关</strong></p>
<p>MockMvc没有区分不同类型的参数，所以<code>param</code>，<code>formParam</code>和<code>queryParam</code>目前只是委托给MockMvc中的param。 <code>formParam</code>自动添加<code>application / x-www-form-urlencoded</code>内容类型的头部，就像标准的Rest Assured一样。</p>
<h2 id="23-Scala支持"><a href="#23-Scala支持" class="headerlink" title="23.Scala支持"></a>23.Scala支持</h2><p>REST Assured 2.6.0引入了将“别名”添加到“then”方法的<a href="http://dl.bintray.com/johanhaleby/generic/scala-support-3.0.1-dist.zip" target="_blank" rel="noopener">scala-support</a>模块定义在<a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/response/Response.html" target="_blank" rel="noopener">Response</a>或<a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/response/MockMvcResponse.html" target="_blank" rel="noopener">MockMvcResponse</a>中调用“Then”。这样做的原因是<code>then</code>在将来可能是Scala中的保留关键字，并且当使用具有此名称的方法时，编译器会发出警告。要启用<code>Then</code>，只需从<code>scala-support</code>模块导入<code>io.restassured.module.scala.RestAssuredSupport.AddThenToResponse</code>类。例如：</p>
<pre><code class="java">import io.restassured.RestAssured.when
import io.restassured.module.scala.RestAssuredSupport.AddThenToResponse
import org.hamcrest.Matchers.equalTo
import org.junit.Test

@Test
def `trying out rest assured in scala with implicit conversion`() {
  when().
          get(&quot;/greetJSON&quot;).
  Then().
          statusCode(200).
          body(&quot;key&quot;, equalTo(&quot;value&quot;))
}</code></pre>
<p>注意：同样支持 <a href="#spring-mock-mvc-module">Spring Mock Mvc Module</a>.</p>
<p>可以像这样使用它：</p>
<p><strong>SBT</strong></p>
<pre><code class="scala">libraryDependencies += &quot;io.rest-assured&quot; % &quot;scala-support&quot; % &quot;3.0.1&quot;</code></pre>
<p><strong>Maven:</strong></p>
<pre><code class="xml">&lt;dependency&gt;
    &lt;groupId&gt;io.rest-assured&lt;/groupId&gt;
    &lt;artifactId&gt;scala-support&lt;/artifactId&gt;
    &lt;version&gt;3.0.1&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p><strong>Gradle:</strong></p>
<pre><code class="gradle">testCompile &#39;io.rest-assured:scala-support:3.0.1&#39;</code></pre>
<p><strong>No build manager:</strong><br>手动下载 <a href="http://dl.bintray.com/johanhaleby/generic/scala-support-3.0.1-dist.zip" target="_blank" rel="noopener">distribution file</a> 。</p>
<h2 id="24-Kotlin支持"><a href="#24-Kotlin支持" class="headerlink" title="24.Kotlin支持"></a>24.Kotlin支持</h2><p>Kotlin是由<a href="https://www.jetbrains.com/" target="_blank" rel="noopener">JetBrains</a>开发的一种语言，它与Java和REST Assured非常好地集成。当使用它与REST Assured有一件事，必须逃避<code>when</code>，因为它是Kotlin中的保留关键字。例如：</p>
<pre><code class="kotlin">Test fun kotlin_rest_assured_example() {
    given().
            param(&quot;firstName&quot;, &quot;Johan&quot;).
            param(&quot;lastName&quot;, &quot;Haleby&quot;).
    `when`().
            get(&quot;/greeting&quot;).
    then().
            statusCode(200).
            body(&quot;greeting.firstName&quot;, equalTo(&quot;Johan&quot;)).
            body(&quot;greeting.lastName&quot;, equalTo(&quot;Haleby&quot;))
}</code></pre>
<p>为了解决这个问题，创建一个<a href="https://kotlinlang.org/docs/reference/extensions.html" target="_blank" rel="noopener">extension function</a>，创建一个别名为<code>when</code>时叫做<code>When</code>：</p>
<pre><code class="kotlin">fun RequestSpecification.When(): RequestSpecification {
    return this.`when`()
}</code></pre>
<p>代码现在可以像这样写：</p>
<pre><code class="kotlin">Test fun kotlin_rest_assured_example() {
    given().
            param(&quot;firstName&quot;, &quot;Johan&quot;).
            param(&quot;lastName&quot;, &quot;Haleby&quot;).
    When().
            get(&quot;/greeting&quot;).
    then().
            statusCode(200).
            body(&quot;greeting.firstName&quot;, equalTo(&quot;Johan&quot;)).
            body(&quot;greeting.lastName&quot;, equalTo(&quot;Haleby&quot;))
}</code></pre>
<p>注意，我们不需要任何转义。有关更多详细信息，请参阅<a href="http://code.haleby.se/2015/11/06/rest-assured-with-kotlin/" target="_blank" rel="noopener">this</a>博客文章。</p>
<h2 id="25-更多信息"><a href="#25-更多信息" class="headerlink" title="25.更多信息"></a>25.更多信息</h2><p><strong>其他相关信息，请参考</strong> </p>
<ul>
<li><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/index.html" target="_blank" rel="noopener">javadoc</a>:</li>
<li><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/RestAssured.html" target="_blank" rel="noopener">RestAssured</a></li>
<li><a href="http://static.javadoc.io/io.restassured/spring-mock-mvc/3.0.1/io/restassured/module/mockmvc/RestAssuredMockMvc.html" target="_blank" rel="noopener">RestAssuredMockMvc Javadoc</a></li>
<li><a href="http://static.javadoc.io/io.rest-assured/rest-assured/3.0.1/io/restassured/specification/package-summary.html" target="_blank" rel="noopener">Specification package</a></li>
</ul>
<p><strong>一些代码示例:</strong></p>
<ul>
<li><a href="https://github.com/rest-assured/rest-assured/tree/master/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java" target="_blank" rel="noopener">tests</a></li>
<li><a href="https://github.com/rest-assured/rest-assured/blob/master/json-path/src/test/java/io/restassured/path/json/JsonPathTest.java" target="_blank" rel="noopener">JsonPathTest</a></li>
<li><a href="https://github.com/rest-assured/rest-assured/blob/master/xml-path/src/test/java/io/restassured/path/xml/XmlPathTest.java" target="_blank" rel="noopener">XmlPathTest</a></li>
</ul>

      
       <hr><span style="font-style: italic;color: gray;"> 转载请注明来源，欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论，也可以邮件至 pgmanor@qq.com </span>
    </div>
</article>


<p>
    <a  class="dashang" onclick="dashangToggle()">赏</a>
</p>


<div class="article_copyright">
    <p><span class="copy-title">文章标题:</span>rest-assured wiki翻译</p>
    <p><span class="copy-title">字数:</span><span class="post-count">19.2k</span></p>
    <p><span class="copy-title">本文作者:</span><a  title="pgmanor">pgmanor</a></p>
    <p><span class="copy-title">发布时间:</span>2020-12-31, 00:00:00</p>
    <p><span class="copy-title">最后更新:</span>2020-12-15, 23:13:04</p>
    <span class="copy-title">原始链接:</span><a class="post-url" href="/blog/2020/12/31/blog-rest-assured-wiki-info/" title="rest-assured wiki翻译">https://pgmanor.gitee.io/blog/2020/12/31/blog-rest-assured-wiki-info/</a>
    <p>
        <span class="copy-title">版权声明:</span><i class="fa fa-creative-commons"></i> <a rel="license noopener" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" title="CC BY-NC-SA 4.0 International" target = "_blank">&#34;署名-非商用-相同方式共享 4.0&#34;</a> 转载请保留原文链接及作者。
    </p>
</div>



    <div id="comments"></div>

<script src="/blog/js/valine.min.js"></script>

<script type="text/javascript">
    new Valine({
        el: '#comments',
        appId: 'g5VDso59rLvb68pq56BNnQ7A-gzGzoHsz',
        appKey: '2bebBs4aVT95Btj4j9zJve2O',
        placeholder: '说点什么...',
        avatar: 'monsterid',
        visitor : 'false'
    })
</script>




    




    </div>
    <div class="copyright">
        <p class="footer-entry">©2021 pgmanor</p>
<!--<p class="footer-entry">Built with <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/yelog/hexo-theme-3-hexo" target="_blank">3-hexo</a> theme</p>-->

    </div>
    <div class="full-toc">
        <button class="full" data-title="切换全屏 快捷键 s"><span class="min "></span></button>
<button class="post-toc-menu" data-title="打开TOC 快捷键 w"><span class="post-toc-menu-icons"></span></button>
<div class="post-toc"><span class="post-toc-title">目录</span>
    <div class="post-toc-content">

    </div>
</div>
<a class="" id="rocket" ></a>

    </div>
</div>
<div class="acParent"></div>

<div class="hide_box" onclick="dashangToggle()"></div>
<div class="shang_box">
    <a class="shang_close"  onclick="dashangToggle()">×</a>
    <div class="shang_tit">
        <p>喜欢就点赞,疼爱就打赏</p>
    </div>
    <div class="shang_payimg">
        <div class="pay_img">
            <img src="/blog/img/alipay.jpg" class="alipay" title="扫码支持">
            <img src="/blog/img/weixin.jpg" class="weixin" title="扫码支持">
        </div>
    </div>
    <div class="shang_payselect">
        <span><label><input type="radio" name="pay" checked value="alipay">支付宝</label></span><span><label><input type="radio" name="pay" value="weixin">微信</label></span>
    </div>
</div>


</body>
<script src="/blog/js/jquery.pjax.js?v=1.0.1x" ></script>

<script src="/blog/js/script.js?v=1.0.1x" ></script>
<script>
    var img_resize = 'default';
    /*作者、标签的自动补全*/
    $(function () {
        $('.search').AutoComplete({
            'data': ['@pgmanor','#AQS','#attr','#aysnc','#beanmap','#bigdecimal','#blog','#chrome','#dict','#dll','#doc','#docker','#domain','#elementadmin','#es','#excel','#farm','#fastjson','#func','#git','#github','#guide','#hadoop','#hexo','#idea','#initialzr','#jackson','#java','#jboss','#jdni','#jetbrains','#jfinalshell','#joplin','#JPA','#junit','#jupyter','#keepavlie','#kill','#linux','#LocalDate','#lock','#markdown','#maven','#message','#mock','#mq','#mycat','#mysql','#nginx','#notebook','#postman','#powermock','#python','#redis','#rest','#sharding-jdbc','#spark','#springboot','#testng','#tornado','#track','#transactional','#uuid','#vuepress','#web','#windows','#zookeeper','#分库分表','#分页','#加密','#启动','#工具','#并发','#序列化','#微服务','#性能分析','#手册','#有道云','#模板','#百度云盘','#算法','#面试','#项目',],
            'itemHeight': 20,
            'width': 418
        }).AutoComplete('show');
    })
    function initArticle() {
        /*渲染对应的表格样式*/
        
            $(".post .pjax table").addClass("green_title");
        

        /*渲染打赏样式*/
        
        $("input[name=pay]").on("click", function () {
            if($("input[name=pay]:checked").val()=="weixin"){
                $(".shang_box .shang_payimg .pay_img").addClass("weixin_img");
            } else {
                $(".shang_box .shang_payimg .pay_img").removeClass("weixin_img");
            }
        })
        

        /*高亮代码块行号*/
        
        $('pre code').each(function(){
            var lines = $(this).text().trim().split('\n').length, widther='';
            if (lines>99) {
                widther = 'widther'
            }
            var $numbering = $('<ul/>').addClass('pre-numbering ' + widther).attr("unselectable","on");
            $(this).addClass('has-numbering ' + widther)
                    .parent()
                    .append($numbering);
            for(var i=1;i<=lines;i++){
                $numbering.append($('<li/>').text(i));
            }
        });
        

        /*访问数量*/
        
        $.getScript("//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js");
        

        /*代码高亮，行号对齐*/
        $('.pre-numbering').css('line-height',$('.has-numbering').css('line-height'));

        
        
    }

    /*打赏页面隐藏与展示*/
    
    function dashangToggle() {
        $(".shang_box").fadeToggle();
        $(".hide_box").fadeToggle();
    }
    

</script>

<!--加入行号的高亮代码块样式-->

<style>
    pre{
        position: relative;
        margin-bottom: 24px;
        border-radius: 10px;
        border: 1px solid #e2dede;
        background: #FFF;
        overflow: hidden;
    }
    code.has-numbering{
        margin-left: 30px;
    }
    code.has-numbering.widther{
        margin-left: 35px;
    }
    .pre-numbering{
        margin: 0px;
        position: absolute;
        top: 0;
        left: 0;
        width: 20px;
        padding: 0.5em 3px 0.7em 5px;
        border-right: 1px solid #C3CCD0;
        text-align: right;
        color: #AAA;
        background-color: #fafafa;
    }
    .pre-numbering.widther {
        width: 35px;
    }
</style>

<!--自定义样式设置-->
<style>
    
    
    .nav {
        width: 442px;
    }
    .nav.fullscreen {
        margin-left: -442px;
    }
    .nav-left {
        width: 120px;
    }
    
    
    @media screen and (max-width: 1468px) {
        .nav {
            width: 442px;
        }
        .nav.fullscreen {
            margin-left: -442px;
        }
        .nav-left {
            width: 150px;
        }
    }
    
    
    @media screen and (max-width: 1024px) {
        .nav {
            width: 442px;
            margin-left: -442px
        }
        .nav.fullscreen {
            margin-left: 0;
        }
        .nav .hide-list.fullscreen {
            left: 442px
        }
    }
    
    @media screen and (max-width: 426px) {
        .nav {
            width: 100%;
        }
        .nav-left {
            width: 100%;
        }
    }
    
    
    .nav-right .title-list nav a .post-title, .nav-right .title-list #local-search-result a .post-title {
        color: #383636;
    }
    
    
    .nav-right .title-list nav a .post-date, .nav-right .title-list #local-search-result a .post-date {
        color: #5e5e5f;
    }
    
    
    .nav-right nav a.hover, #local-search-result a.hover{
        background-color: #e2e0e0;
    }
    
    

    /*列表样式*/
    
    .post .pjax article .article-entry>ol, .post .pjax article .article-entry>ul, .post .pjax article>ol, .post .pjax article>ul{
        border: #e2dede solid 1px;
        border-radius: 10px;
        padding: 10px 32px 10px 56px;
    }
    .post .pjax article .article-entry li>ol, .post .pjax article .article-entry li>ul,.post .pjax article li>ol, .post .pjax article li>ul{
        padding-top: 5px;
        padding-bottom: 5px;
    }
    .post .pjax article .article-entry>ol>li, .post .pjax article .article-entry>ul>li,.post .pjax article>ol>li, .post .pjax article>ul>li{
        margin-bottom: auto;
        margin-left: auto;
    }
    .post .pjax article .article-entry li>ol>li, .post .pjax article .article-entry li>ul>li,.post .pjax article li>ol>li, .post .pjax article li>ul>li{
        margin-bottom: auto;
        margin-left: auto;
    }
    

    /* 背景图样式 */
    
    


    /*引用块样式*/
    

    /*文章列表背景图*/
    

    
</style>






<div class="mobile-menus-out" >

</div>
<div class="mobile-menus">
    
    
    
    <a class="dynamic-menu " target="_blank"  href="https://www.iworkh.com/">iworkh</a>
    
    
    <a class="dynamic-menu " target="_blank"  href="https://gitee.com/pgmanor">gitee</a>
    
</div>


<div style="position:absolute; bottom: 0; right: 0;">
    <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=150 height=40 src="//music.163.com/outchain/player?type=2&id=1323150930&auto=0&height=32"></iframe>
</div>

</html>
